/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "gamesequence/gamesequence.h" #include "ui/ui.h" #include "menuui/techmenu.h" #include "render/3d.h" #include "io/key.h" #include "missionui/missionscreencommon.h" #include "gamesnd/gamesnd.h" #include "graphics/font.h" #include "io/mouse.h" #include "ui/uidefs.h" #include "gamehelp/contexthelp.h" #include "globalincs/alphacolors.h" #include "anim/animplay.h" #include "anim/packunpack.h" #include "localization/localize.h" #include "lighting/lighting.h" #include "sound/fsspeech.h" #include "playerman/player.h" #include "parse/parselo.h" #include "ship/ship.h" #include "weapon/weapon.h" #define REVOLUTION_RATE 5.2f #define NUM_BUTTONS 16 #define NUM_TABS 3 #define LIST_BUTTONS_MAX 42 #define SHIPS_DATA_MODE (1<<0) #define WEAPONS_DATA_MODE (1<<1) #define SPECIES_DATA_MODE (1<<2) #define WEAPONS_SPECIES_DATA_MODE (WEAPONS_DATA_MODE | SPECIES_DATA_MODE) #define SHIPS_DATA_TAB 0 #define WEAPONS_DATA_TAB 1 #define INTEL_DATA_TAB 2 #define TECH_DATABASE_TAB 3 #define SIMULATOR_TAB 4 #define CUTSCENES_TAB 5 #define CREDITS_TAB 6 #define SCROLL_LIST_UP 7 #define SCROLL_LIST_DOWN 8 #define SCROLL_INFO_UP 9 #define SCROLL_INFO_DOWN 10 #define PREV_ENTRY_BUTTON 11 #define NEXT_ENTRY_BUTTON 12 #define HELP_BUTTON 13 #define OPTIONS_BUTTON 14 #define EXIT_BUTTON 15 //#define PREV_ENTRY_BUTTON2 16 //#define NEXT_ENTRY_BUTTON2 17 #define REPEAT (1<<0) #define NO_MOUSE_OVER_SOUND (1<<1) // indicies for coords #define SHIP_X_COORD 0 #define SHIP_Y_COORD 1 #define SHIP_W_COORD 2 #define SHIP_H_COORD 3 // background filename for species // note weapon filename is now same as ship filename char *Tech_background_filename[GR_NUM_RESOLUTIONS] = { "TechShipData", "2_TechShipData" }; char *Tech_mask_filename[GR_NUM_RESOLUTIONS] = { "TechShipData-M", "2_TechShipData-M" }; char *Tech_slider_filename[GR_NUM_RESOLUTIONS] = { "slider", "2_slider" }; int Tech_list_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 27, 98, 161, 234 }, { // GR_1024 43, 157, 253, 374 } }; int Tech_ship_display_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 239, 98, 393, 222 }, { // GR_1024 382, 158, 629, 355 } }; int Tech_desc_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 29, 347, 365, 125 }, { // GR_1024 47, 555, 584, 200 } }; int Tech_ani_coords[GR_NUM_RESOLUTIONS][2] = { { // GR_640 196, 115 }, { // GR_1024 449, 245 } }; /*int Tech_desc_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 24, 139, 376, 281 }, { // GR_1024 24, 182, 638, 528 } };*/ int Tech_slider_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 2, 118, 20, 194 }, { // GR_1024 3, 190, 32, 310 } }; // detail backup /* int Tech_detail_backup; int Tech_texture_backup;*/ #define MAX_TEXT_LINES 100 #define MAX_TEXT_LINE_LEN 256 struct techroom_buttons { char *filename; int x, y, xt, yt; int hotspot; int tab; int flags; UI_BUTTON button; // because we have a class inside this struct, we need the constructor below.. techroom_buttons(char *name, int x1, int y1, int xt1, int yt1, int h, int t, int f = 0) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h), tab(t), flags(f) {} }; static techroom_buttons Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = { { // GR_640 techroom_buttons("TDB_04", 406, 384, 447, 393, 4, -1), // ship data tab techroom_buttons("TDB_05", 404, 418, 447, 429, 5, -1), // weapons data tab techroom_buttons("TDB_06", 404, 447, 447, 461, 6, -1), // species data tab techroom_buttons("TDB_00", 7, 3, 37, 7, 0, -1), // technical database tab techroom_buttons("TDB_01", 7, 18, 37, 23, 1, -1), // mission simulator tab techroom_buttons("TDB_02", 7, 34, 37, 38, 2, -1), // cutscenes tab techroom_buttons("TDB_03", 7, 49, 37, 54, 3, -1), // credits tab techroom_buttons("TDB_07", 1, 86, -1, -1, 7, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("TDB_08", 1, 317, -1, -1, 8, SHIPS_DATA_MODE, REPEAT), // next data entry techroom_buttons("TDB_09", 1, 406, -1, -1, 9, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("TDB_10", 1, 447, -1, -1, 10, SHIPS_DATA_MODE, REPEAT), // next data entry //techroom_buttons("TDB_11", 558, 272, -1, -1, 11, WEAPONS_SPECIES_DATA_MODE), // prev data entry //techroom_buttons("TDB_12", 606, 272, -1, -1, 12, WEAPONS_SPECIES_DATA_MODE), // next data entry techroom_buttons("TDB_11a",559, 323, -1, -1, 11, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("TDB_12a",609, 323, -1, -1, 12, SHIPS_DATA_MODE, REPEAT), // next data entry techroom_buttons("TDB_13", 533, 425, 500, 440, 13, -1), // help techroom_buttons("TDB_14", 533, 455, 479, 464, 14, -1), // options techroom_buttons("TDB_15a",571, 425, 588, 413, 15, -1), // exit }, { // GR_1024 techroom_buttons("2_TDB_04", 649, 614, 717, 630, 4, -1), // ship data tab techroom_buttons("2_TDB_05", 646, 669, 717, 687, 5, -1), // weapons data tab techroom_buttons("2_TDB_06", 646, 716, 717, 739, 6, -1), // species data tab techroom_buttons("2_TDB_00", 12, 5, 59, 12, 0, -1), // technical database tab techroom_buttons("2_TDB_01", 12, 31, 59, 37, 1, -1), // mission simulator tab techroom_buttons("2_TDB_02", 12, 56, 59, 62, 2, -1), // cutscenes tab techroom_buttons("2_TDB_03", 12, 81, 59, 88, 3, -1), // credits tab techroom_buttons("2_TDB_07", 1, 138, -1, -1, 7, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("2_TDB_08", 1, 507, -1, -1, 8, SHIPS_DATA_MODE, REPEAT), // next data entry techroom_buttons("2_TDB_09", 1, 649, -1, -1, 9, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("2_TDB_10", 1, 716, -1, -1, 10, SHIPS_DATA_MODE, REPEAT), // next data entry //techroom_buttons("2_TDB_11", 893, 436, -1, -1, 11, WEAPONS_SPECIES_DATA_MODE), // prev data entry //techroom_buttons("2_TDB_12", 970, 436, -1, -1, 12, WEAPONS_SPECIES_DATA_MODE), // next data entry techroom_buttons("2_TDB_11a", 895, 518, -1, -1, 11, SHIPS_DATA_MODE, REPEAT), // prev data entry techroom_buttons("2_TDB_12a", 974, 518, -1, -1, 12, SHIPS_DATA_MODE, REPEAT), // next data entry techroom_buttons("2_TDB_13", 854, 681, 800, 704, 13, -1), // help techroom_buttons("2_TDB_14", 854, 728, 780, 743, 14, -1), // options techroom_buttons("2_TDB_15a", 914, 681, 930, 660, 15, -1), // exit }, }; static UI_WINDOW Ui_window; static UI_BUTTON View_window; //static int Background_bitmap; static int Tech_background_bitmap; //static int Intel_bg_bitmap; // not used now - taylor static int Tab = SHIPS_DATA_TAB; // static int List_size; static int List_offset; static int Select_tease_line; //static int Limit; // not used now - taylor static int Trackball_mode = 1; static int Trackball_active = 0; static matrix Techroom_ship_orient = IDENTITY_MATRIX; // static int Tech_room_ask_for_cd; static int Techroom_show_all = 0; static int Text_size; static int Text_offset; static int Text_line_size[MAX_TEXT_LINES]; static char *Text_lines[MAX_TEXT_LINES]; static int Cur_entry = -1; // this is the current entry selected, using entry indexing static int Cur_entry_index = -1; // this is the current entry selected, using master list indexing static int Techroom_ship_modelnum; static float Techroom_ship_rot; static UI_BUTTON List_buttons[LIST_BUTTONS_MAX]; // buttons for each line of text in list static int Anim_playing_id = -1; static anim_instance *Cur_anim_instance = NULL; static int Palette_bmp; //static int ShipWin01; //static int ShipWin02; //static int ShipWin03; //static int ShipWin04; static ubyte Palette[768]; //static char Palette_name[128]; // not used now - taylor static int Ships_loaded = 0; static int Weapons_loaded = 0; static int Intel_loaded = 0; // out entry data struct & vars typedef struct { int index; // index into the master table that its in (ie Ship_info[]) char* name; // ptr to name string char* desc; // ptr to description string anim* animation; // ptr to the animation int bitmap; // bitmap handle int has_anim; // flag to indicate the presence of an animation for this item int model_num; // model reference handle int textures_loaded; // if the model has textures loaded for it or not (hacky mem management) } tech_list_entry; static tech_list_entry *Ship_list = NULL; static int Ship_list_size = 0; static tech_list_entry *Weapon_list = NULL; static int Weapon_list_size = 0; static tech_list_entry Intel_list[MAX_INTEL_ENTRIES]; static int Intel_list_size = 0; static tech_list_entry *Current_list; // points to currently valid display list static int Current_list_size = 0; // slider stuff static UI_SLIDER2 Tech_slider; //XSTR:OFF /* static char *Intel_anim_filenames[MAX_INTEL_ENTRIES] = { "tech_tpilot.ani", "tech_vasudan.ani", "tech_shivan.ani", }; */ //XSTR:ON // Intelligence master data structs (these get inited @ game startup from species.tbl) intel_data Intel_info[MAX_INTEL_ENTRIES]; int Intel_info_size = 0; // some prototypes to make you happy int techroom_load_ani(anim **animpp, char *name); void tech_common_render(); void techroom_start_anim(); void tech_scroll_list_up(); void tech_scroll_list_down(); //stuff for ht&l, vars and such extern int Cmdline_nohtl; //////////////////////////////////////////////////// // like, functions and stuff void techroom_init_desc(char *src, int w) { Text_size = Text_offset = 0; if (!src) { return; } Text_size = split_str(src, w, Text_line_size, Text_lines, MAX_TEXT_LINES); Assert(Text_size >= 0 && Text_size < MAX_TEXT_LINES); } void techroom_select_new_entry() { Assert(Current_list != NULL); if (Current_list == NULL || Current_list_size <= 0) { Cur_entry_index = Cur_entry = -1; techroom_init_desc(NULL,0); return; } Cur_entry_index = Current_list[Cur_entry].index; Assert( Cur_entry_index >= 0 ); // if we are in the ships tab, load the ship model if (Tab == SHIPS_DATA_TAB) { ship_info *sip = &Ship_info[Cur_entry_index]; // little memory management, kinda hacky but it should keep the techroom at around // 100meg rather than the 700+ it can get to with all ships loaded - taylor for (int i=0; i -1) && (Current_list[i].textures_loaded)) { // don't unload any spot within 5 of current if ( (i < Cur_entry + 5) && (i > Cur_entry - 5) ) continue; mprintf(("TECH ROOM: Dumping excess ship textures...\n")); model_page_out_textures(Current_list[i].model_num); Current_list[i].textures_loaded = 0; } } Techroom_ship_modelnum = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]); Current_list[Cur_entry].model_num = Techroom_ship_modelnum; // page in ship textures properly (takes care of nondimming pixels) model_page_in_textures(Techroom_ship_modelnum, Cur_entry_index); Current_list[Cur_entry].textures_loaded = 1; } else { Techroom_ship_modelnum = -1; Trackball_mode = 0; } // Techroom_ship_rot = PI; techroom_init_desc(Current_list[Cur_entry].desc, Tech_desc_coords[gr_screen.res][SHIP_W_COORD]); fsspeech_play(FSSPEECH_FROM_TECHROOM, Current_list[Cur_entry].desc); techroom_start_anim(); } // write out the current description in the bottom window void techroom_render_desc(int xo, int yo, int ho) { int y, z, len, font_height; char line[MAX_TEXT_LINE_LEN + 1]; font_height = gr_get_font_height(); y = 0; z = Text_offset; while (y + font_height <= ho) { if (z >= Text_size){ break; } len = Text_line_size[z]; if (len > MAX_TEXT_LINE_LEN){ len = MAX_TEXT_LINE_LEN; } strncpy(line, Text_lines[z], len); line[len] = 0; gr_string(xo, yo + y, line); y += font_height; z++; } // maybe output 'more' indicator if ( z < Text_size ) { // can be scrolled down int more_txt_x = Tech_desc_coords[gr_screen.res][0] + (Tech_desc_coords[gr_screen.res][2]/2) - 10; // FIXME should move these to constants since they don't move int more_txt_y = Tech_desc_coords[gr_screen.res][1] + Tech_desc_coords[gr_screen.res][3]; // located below brief text, centered int w, h; gr_get_string_size(&w, &h, XSTR("more", 1469), strlen(XSTR("more", 1469))); gr_set_color_fast(&Color_black); gr_rect(more_txt_x-2, more_txt_y, w+3, h); gr_set_color_fast(&Color_red); gr_string(more_txt_x, more_txt_y, XSTR("more", 1469)); // base location on the input x and y? } } // new version of weapons void techroom_weapons_render2(float frametime) { // render common stuff tech_common_render(); // render the animation if(Current_list[Cur_entry].animation != NULL) { // JAS: This code is hacked to allow the animation to use all 256 colors extern int Palman_allow_any_color; Palman_allow_any_color = 1; anim_render_all(0, frametime); Palman_allow_any_color = 0; } // if our active item has a bitmap instead of an animation, draw it if((Cur_entry > 0) && (Current_list[Cur_entry].animation == NULL) && (Current_list[Cur_entry].bitmap >= 0)){ gr_set_bitmap(Current_list[Cur_entry].bitmap); gr_bitmap(Tech_ani_coords[gr_screen.res][0], Tech_ani_coords[gr_screen.res][1]); } } // renders the stuff common to all 3 tech room tabs void tech_common_render() { char buf[256]; int y, z, font_height; // render description in its box gr_set_color_fast(&Color_text_normal); techroom_render_desc(Tech_desc_coords[gr_screen.res][SHIP_X_COORD], Tech_desc_coords[gr_screen.res][SHIP_Y_COORD], Tech_desc_coords[gr_screen.res][SHIP_H_COORD]); font_height = gr_get_font_height(); // draw the list of entries y = 0; z = List_offset; while (y + font_height <= Tech_list_coords[gr_screen.res][SHIP_H_COORD]) { if (z >= Current_list_size) { break; } if (z == Cur_entry) { gr_set_color_fast(&Color_text_selected); } else if (z == Select_tease_line) { gr_set_color_fast(&Color_text_subselected); } else { gr_set_color_fast(&Color_text_normal); } memset( buf, 0, sizeof(buf) ); strncpy(buf, Current_list[z].name, sizeof(buf) - 1); if (Lcl_gr) lcl_translate_ship_name(buf); gr_force_fit_string(buf, 255, Tech_list_coords[gr_screen.res][SHIP_W_COORD]); gr_string(Tech_list_coords[gr_screen.res][SHIP_X_COORD], Tech_list_coords[gr_screen.res][SHIP_Y_COORD] + y, buf); List_buttons[z - List_offset].update_dimensions(Tech_list_coords[gr_screen.res][SHIP_X_COORD], Tech_list_coords[gr_screen.res][SHIP_Y_COORD] + y, Tech_list_coords[gr_screen.res][SHIP_W_COORD], font_height); List_buttons[z - List_offset].enable(1); y += font_height; z++; } // disable the rest of the list buttons z -= List_offset; while (z < LIST_BUTTONS_MAX) { List_buttons[z++].disable(); } } void techroom_ships_render(float frametime) { // render all the common stuff tech_common_render(); if(Cur_entry_index == -1) return; // now render the trackball ship, which is unique to the ships tab float rev_rate = REVOLUTION_RATE; angles rot_angles, view_angles; int z; ship_info *sip = &Ship_info[Cur_entry_index]; // get correct revolution rate z = sip->flags; if (z & SIF_BIG_SHIP) { rev_rate *= 1.7f; } if (z & SIF_HUGE_SHIP) { rev_rate *= 3.0f; } // rotate the ship as much as required for this frame Techroom_ship_rot += PI2 * frametime / rev_rate; while (Techroom_ship_rot > PI2){ Techroom_ship_rot -= PI2; } // turn off fogging //gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); // reorient ship if (Trackball_active) { int dx, dy; matrix mat1, mat2; if (Trackball_active) { mouse_get_delta(&dx, &dy); if (dx || dy) { vm_trackball(-dx, -dy, &mat1); vm_matrix_x_matrix(&mat2, &mat1, &Techroom_ship_orient); Techroom_ship_orient = mat2; } } } else { // setup stuff needed to render the ship view_angles.p = -0.6f; view_angles.b = 0.0f; view_angles.h = 0.0f; vm_angles_2_matrix(&Techroom_ship_orient, &view_angles); rot_angles.p = 0.0f; rot_angles.b = 0.0f; rot_angles.h = Techroom_ship_rot; vm_rotate_matrix_by_angles(&Techroom_ship_orient, &rot_angles); } gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD]); // render the ship g3_start_frame(1); g3_set_view_matrix(&sip->closeup_pos, &vmd_identity_matrix, sip->closeup_zoom * 1.3f); if (!Cmdline_nohtl) { gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance); gr_set_view_matrix(&Eye_position, &Eye_matrix); } // lighting for techroom light_reset(); vec3d light_dir = vmd_zero_vector; light_dir.xyz.y = 1.0f; light_add_directional(&light_dir, 0.85f, 1.0f, 1.0f, 1.0f); light_rotate_all(); // lighting for techroom model_clear_instance(Techroom_ship_modelnum); model_set_detail_level(0); model_render(Techroom_ship_modelnum, &Techroom_ship_orient, &vmd_zero_vector, MR_LOCK_DETAIL | MR_AUTOCENTER); if (!Cmdline_nohtl) { gr_end_view_matrix(); gr_end_proj_matrix(); } g3_end_frame(); gr_reset_clip(); } // select previous entry in current list void tech_prev_entry() { Cur_entry--; if (Cur_entry < 0) { Cur_entry = Current_list_size - 1; // scroll to end of list List_offset = Cur_entry - Tech_list_coords[gr_screen.res][SHIP_H_COORD] / gr_get_font_height() + 1; if (List_offset < 0) { // this happens when there are not enough items to scroll List_offset = 0; } Tech_slider.force_currentItem(Tech_slider.get_numberItems()); } else { // maybe adjust list position by 1 if (List_offset > Cur_entry) { tech_scroll_list_up(); Tech_slider.forceUp(); } } techroom_select_new_entry(); gamesnd_play_iface(SND_SCROLL); } // select next entry in current list void tech_next_entry() { Cur_entry++; if (Cur_entry >= Current_list_size) { Cur_entry = 0; // scroll to beginning of list List_offset = 0; Tech_slider.force_currentItem(Cur_entry); } else { // maybe adjust list position by 1 if (List_offset + Tech_list_coords[gr_screen.res][SHIP_H_COORD] / gr_get_font_height() <= Cur_entry) { tech_scroll_list_down(); Tech_slider.forceDown(); } } techroom_select_new_entry(); gamesnd_play_iface(SND_SCROLL); } void tech_scroll_info_up() { if (Text_offset) { Text_offset--; gamesnd_play_iface(SND_SCROLL); } else { gamesnd_play_iface(SND_GENERAL_FAIL); } } void tech_scroll_info_down() { int h; if (Tab == SHIPS_DATA_TAB){ h = Tech_desc_coords[gr_screen.res][SHIP_H_COORD]; } else { h = Tech_desc_coords[gr_screen.res][3]; } if (Text_offset + h / gr_get_font_height() < Text_size) { Text_offset++; gamesnd_play_iface(SND_SCROLL); } else { gamesnd_play_iface(SND_GENERAL_FAIL); } } void tech_scroll_list_up() { //int last; if (List_offset > 0) { List_offset--; //last = List_offset + Tech_list_coords[gr_screen.res][SHIP_H_COORD] / gr_get_font_height() - 1; gamesnd_play_iface(SND_SCROLL); } else { gamesnd_play_iface(SND_GENERAL_FAIL); } } void tech_scroll_list_down() { if (List_offset + Tech_list_coords[gr_screen.res][SHIP_H_COORD] / gr_get_font_height() < Current_list_size) { List_offset++; gamesnd_play_iface(SND_SCROLL); } else { gamesnd_play_iface(SND_GENERAL_FAIL); } } // this doesn't do a thing... void tech_ship_scroll_capture() { techroom_select_new_entry(); } // this is obsolete - see techroom_weapons_render2(...) //If this is obsolete, why isn't it commented out? -WMC /* void techroom_weapons_render(float frametime) { gr_set_color_fast(&Color_text_normal); techroom_render_desc(Tech_desc_coords[gr_screen.res][0], Tech_desc_coords[gr_screen.res][1], Tech_desc_coords[gr_screen.res][3]); { // JAS: This code is hacked to allow the animation to use all 256 colors extern int Palman_allow_any_color; Palman_allow_any_color = 1; anim_render_all(0, frametime); Palman_allow_any_color = 0; } // if our active item has a bitmap instead of an animation, draw it if((Cur_entry >= 0) && (Current_list[Cur_entry].animation == NULL) && (Current_list[Cur_entry].bitmap >= 0)){ gr_set_bitmap(Current_list[Cur_entry].bitmap); gr_bitmap(Tech_ani_coords[gr_screen.res][0], Tech_ani_coords[gr_screen.res][1]); } }*/ void techroom_intel_render(float frametime) { tech_common_render(); { // JAS: This code is hacked to allow the animation to use all 256 colors extern int Palman_allow_any_color; Palman_allow_any_color = 1; anim_render_all(0, frametime); Palman_allow_any_color = 0; } // if our active item has a bitmap instead of an animation, draw it if((Cur_entry >= 0) && (Current_list[Cur_entry].animation == NULL) && (Current_list[Cur_entry].bitmap >= 0)){ gr_set_bitmap(Current_list[Cur_entry].bitmap); gr_bitmap(Tech_ani_coords[gr_screen.res][0], Tech_ani_coords[gr_screen.res][1]); } } void techroom_stop_anim(int id) { if (Cur_anim_instance && (id != Anim_playing_id)) { anim_stop_playing(Cur_anim_instance); Cur_anim_instance = NULL; } } void techroom_start_anim() { int id; anim *animp; anim_play_struct aps; if (Cur_entry < 0) { techroom_stop_anim(-1); Anim_playing_id = -1; } if (Tab == WEAPONS_DATA_TAB) { id = Cur_entry; } else { id = Cur_entry + 2000; // this offset is arbitrary? } techroom_stop_anim(id); // if we actually have an animation if(Current_list[Cur_entry].animation != NULL){ animp = Current_list[Cur_entry].animation; if (id != Anim_playing_id) { Anim_playing_id = -1; if (animp) { anim_play_init(&aps, animp, Tech_ani_coords[gr_screen.res][0], Tech_ani_coords[gr_screen.res][1]); aps.looped = 1; Cur_anim_instance = anim_play(&aps); Anim_playing_id = id; } if (animp) { memcpy(Palette, animp->palette, 384); gr_set_palette(animp->name, Palette, 1); } } } } void techroom_change_tab(int num) { int i, multi = 0, mask, mask2, font_height, max_num_entries_viewable; Tab = num; // Assert(Current_list_size >= 0); List_offset = 0; Cur_entry = 0; multi = Player->flags & PLAYER_FLAGS_IS_MULTI; for (i=0; iflags & PLAYER_FLAGS_IS_MULTI) { Buttons[gr_screen.res][SIMULATOR_TAB].button.disable(); Buttons[gr_screen.res][CUTSCENES_TAB].button.disable(); } switch (Tab) { case SHIPS_DATA_TAB: mask = multi ? SIF_IN_TECH_DATABASE_M : SIF_IN_TECH_DATABASE; mask2 = multi ? SIF2_DEFAULT_IN_TECH_DATABASE_M : SIF2_DEFAULT_IN_TECH_DATABASE; // load ship info if necessary if ( Ships_loaded == 0 ) { if (Ship_list == NULL) { Ship_list = new tech_list_entry[Num_ship_classes]; if (Ship_list == NULL) Error(LOCATION, "Couldn't init ships list!"); } Ship_list_size = 0; for (i=0; i max_num_entries_viewable ? Current_list_size-max_num_entries_viewable : 0); // no anim to start here break; case WEAPONS_DATA_TAB: // load weapon info & anims if necessary if ( Weapons_loaded == 0 ) { if (Weapon_list == NULL) { Weapon_list = new tech_list_entry[Num_weapon_types]; if (Weapon_list == NULL) Error(LOCATION, "Couldn't init ships list!"); } Weapon_list_size = 0; mask = multi ? WIF_PLAYER_ALLOWED : WIF_IN_TECH_DATABASE; mask2 = WIF2_DEFAULT_IN_TECH_DATABASE; for (i=0; i 0) && (!strcmp(Weapon_info[i].tech_desc, Weapon_list[Weapon_list_size-1].desc))) { // continue; //} // we have a weapon that should be in the tech db, so fill out the entry struct Weapon_list[Weapon_list_size].index = i; Weapon_list[Weapon_list_size].desc = Weapon_info[i].tech_desc; Weapon_list[Weapon_list_size].has_anim = 1; Weapon_list[Weapon_list_size].name = Weapon_info[i].tech_title; Weapon_list[Weapon_list_size].bitmap = -1; Weapon_list[Weapon_list_size].animation = NULL; Weapon_list[Weapon_list_size].model_num = -1; Weapon_list[Weapon_list_size].textures_loaded = 0; if (Weapon_list[Weapon_list_size].name[0] == 0) { Weapon_list[Weapon_list_size].name = Weapon_info[i].name; } // load the weapon animation if(!techroom_load_ani(&Weapon_list[Weapon_list_size].animation, Weapon_info[i].tech_anim_filename)){ Weapon_list[Weapon_list_size].has_anim = 0; Weapon_list[Weapon_list_size].animation = NULL; // hmm. try a bitmap instead Weapon_list[Weapon_list_size].bitmap = bm_load(Weapon_info[i].tech_anim_filename); } Weapon_list_size++; } } // make sure that at least the default entry is cleared out if we didn't grab anything if (Num_weapon_types && !Weapon_list_size) { Weapon_list[0].index = -1; Weapon_list[0].desc = NULL; Weapon_list[0].name = NULL; Weapon_list[0].bitmap = -1; Weapon_list[0].has_anim = 0; Weapon_list[0].animation = NULL; Weapon_list[0].model_num = -1; Weapon_list[0].textures_loaded = 0; } Weapons_loaded = 1; } Current_list = Weapon_list; Current_list_size = Weapon_list_size; font_height = gr_get_font_height(); max_num_entries_viewable = Tech_list_coords[gr_screen.res][SHIP_H_COORD] / font_height; Tech_slider.set_numberItems(Current_list_size > max_num_entries_viewable ? Current_list_size-max_num_entries_viewable : 0); techroom_start_anim(); break; case INTEL_DATA_TAB: // load intel if necessary if ( Intel_loaded == 0 ) { // now populate the entry structs Intel_list_size = 0; for (i=0; i max_num_entries_viewable ? Current_list_size-max_num_entries_viewable : 0); techroom_start_anim(); break; } // reset the entry Cur_entry = 0; techroom_select_new_entry(); } int techroom_button_pressed(int num) { switch (num) { case SHIPS_DATA_TAB: case WEAPONS_DATA_TAB: case INTEL_DATA_TAB: fsspeech_stop(); techroom_change_tab(num); break; case SIMULATOR_TAB: fsspeech_stop(); #if !defined(E3_BUILD) && !defined(PD_BUILD) gamesnd_play_iface(SND_SWITCH_SCREENS); gameseq_post_event(GS_EVENT_SIMULATOR_ROOM); return 1; #else return 0; #endif case CUTSCENES_TAB: fsspeech_stop(); #if !defined(E3_BUILD) && !defined(PD_BUILD) gamesnd_play_iface(SND_SWITCH_SCREENS); gameseq_post_event(GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN); return 1; #else return 0; #endif case CREDITS_TAB: fsspeech_stop(); #if !defined(E3_BUILD) && !defined(PD_BUILD) gamesnd_play_iface(SND_SWITCH_SCREENS); gameseq_post_event(GS_EVENT_CREDITS); return 1; #else return 0; #endif case PREV_ENTRY_BUTTON: tech_prev_entry(); break; case NEXT_ENTRY_BUTTON: tech_next_entry(); break; case SCROLL_LIST_UP: tech_scroll_list_up(); Tech_slider.forceUp(); break; case SCROLL_LIST_DOWN: tech_scroll_list_down(); Tech_slider.forceDown(); break; case SCROLL_INFO_UP: tech_scroll_info_up(); break; case SCROLL_INFO_DOWN: tech_scroll_info_down(); break; case HELP_BUTTON: launch_context_help(); gamesnd_play_iface(SND_HELP_PRESSED); break; case OPTIONS_BUTTON: gamesnd_play_iface(SND_SWITCH_SCREENS); gameseq_post_event(GS_EVENT_OPTIONS_MENU); break; case EXIT_BUTTON: fsspeech_stop(); gamesnd_play_iface(SND_COMMIT_PRESSED); gameseq_post_event(GS_EVENT_MAIN_MENU); break; } return 0; } int techroom_load_ani(anim **animpp, char *name) { int load_attempts = 0; char anim_filename[64] = "2_"; // hi-res support // (i don't think there are any hi-res anims for these tho) if (gr_screen.res == GR_1024) { strcat(anim_filename, name); } else { strcpy(anim_filename, name); } while(1) { if ( load_attempts++ > 5 ) { // Tech_room_ask_for_cd = 0; return 0; } *animpp = anim_load(anim_filename, CF_TYPE_ANY, 1); if ( *animpp ) { return 1; } else if (gr_screen.res == GR_1024) { // try to load low-res version if hi-res failed *animpp = anim_load(name, CF_TYPE_ANY, 1); if (*animpp) { return 1; } } // couldn't load animation, ask user to insert CD (if necessary) // if ( Tech_room_ask_for_cd ) { // if ( game_do_cd_check() == 0 ) { // Tech_room_ask_for_cd = 0; // break; // } // } } // bogus return 0; } void techroom_intel_init() { int rval, temp; static int inited = 0; if (inited) return; // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "species.tbl", rval)); lcl_ext_close(); return; } read_file_text("species.tbl", CF_TYPE_TABLES); reset_parse(); Intel_info_size = 0; while (optional_string("$Entry:")) { Assert(Intel_info_size < MAX_INTEL_ENTRIES); if (Intel_info_size >= MAX_INTEL_ENTRIES) { mprintf(("TECHMENU: Too many intel entries!\n")); break; } Intel_info[Intel_info_size].flags = IIF_DEFAULT_VALUE; required_string("$Name:"); stuff_string(Intel_info[Intel_info_size].name, F_NAME, NAME_LENGTH); required_string("$Anim:"); stuff_string(Intel_info[Intel_info_size].anim_filename, F_NAME, NAME_LENGTH); required_string("$AlwaysInTechRoom:"); stuff_int(&temp); if (temp) { // set default to align with what we read - Goober5000 Intel_info[Intel_info_size].flags |= IIF_IN_TECH_DATABASE; Intel_info[Intel_info_size].flags |= IIF_DEFAULT_IN_TECH_DATABASE; } required_string("$Description:"); stuff_string(Intel_info[Intel_info_size].desc, F_MULTITEXT, TECH_INTEL_DESC_LEN); Intel_info_size++; } inited = 1; // close localization lcl_ext_close(); } void techroom_init() { int i, idx; techroom_buttons *b; /* gr_reset_clip(); gr_clear(); Mouse_hidden++; gr_flip(); Mouse_hidden--;*/ Ships_loaded = 0; Weapons_loaded = 0; Intel_loaded = 0; Techroom_show_all = 0; // Tech_room_ask_for_cd = 1; // backup and bash detail level stuff //I don't think we need this anymore /*Tech_detail_backup = Detail.detail_distance; Detail.detail_distance = MAX_DETAIL_LEVEL; Tech_texture_backup = Detail.hardware_textures; Detail.hardware_textures = MAX_DETAIL_LEVEL;*/ /* Palette_bmp = bm_load("TechDataPalette"); Assert(Palette_bmp); bm_get_palette(Palette_bmp, Palette, Palette_name); // get the palette for this bitmap gr_set_palette(Palette_name, Palette, 1); */ // unflag fullneb //WMC - shouldn't need this //The_mission.flags &= ~MISSION_FLAG_FULLNEB; // set up UI stuff Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0); Ui_window.set_mask_bmap(Tech_mask_filename[gr_screen.res]); Tech_background_bitmap = bm_load(Tech_background_filename[gr_screen.res]); if (Tech_background_bitmap < 0) { // failed to load bitmap, not a good thing Error(LOCATION,"Couldn't load techroom background bitmap"); } for (i=0; ibutton.create(&Ui_window, "", b->x, b->y, 60, 30, b->flags & REPEAT, 1); // set up callback for when a mouse first goes over a button if (b->filename) { b->button.set_bmaps(b->filename); // if ( !(b->flags & NO_MOUSE_OVER_SOUND) ) { b->button.set_highlight_action(common_play_highlight_sound); // } } else { b->button.hide(); } b->button.link_hotspot(b->hotspot); } // common tab button text Ui_window.add_XSTR("Technical Database", 1055, Buttons[gr_screen.res][TECH_DATABASE_TAB].xt, Buttons[gr_screen.res][TECH_DATABASE_TAB].yt, &Buttons[gr_screen.res][TECH_DATABASE_TAB].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Mission Simulator", 1056, Buttons[gr_screen.res][SIMULATOR_TAB].xt, Buttons[gr_screen.res][SIMULATOR_TAB].yt, &Buttons[gr_screen.res][SIMULATOR_TAB].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Cutscenes", 1057, Buttons[gr_screen.res][CUTSCENES_TAB].xt, Buttons[gr_screen.res][CUTSCENES_TAB].yt, &Buttons[gr_screen.res][CUTSCENES_TAB].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Credits", 1058, Buttons[gr_screen.res][CREDITS_TAB].xt, Buttons[gr_screen.res][CREDITS_TAB].yt, &Buttons[gr_screen.res][CREDITS_TAB].button, UI_XSTR_COLOR_GREEN); // common ship/weapon/intel text Ui_window.add_XSTR("Ships", 293, Buttons[gr_screen.res][SHIPS_DATA_TAB].xt, Buttons[gr_screen.res][SHIPS_DATA_TAB].yt, &Buttons[gr_screen.res][SHIPS_DATA_TAB].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Weapons", 1553, Buttons[gr_screen.res][WEAPONS_DATA_TAB].xt, Buttons[gr_screen.res][WEAPONS_DATA_TAB].yt, &Buttons[gr_screen.res][WEAPONS_DATA_TAB].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Intelligence", 1066, Buttons[gr_screen.res][INTEL_DATA_TAB].xt, Buttons[gr_screen.res][INTEL_DATA_TAB].yt, &Buttons[gr_screen.res][INTEL_DATA_TAB].button, UI_XSTR_COLOR_GREEN); // common help/options/commit text // NK: removed these two text labels on Tech screen update 4/26/99 // Ui_window.add_XSTR("Help", 928, Buttons[gr_screen.res][HELP_BUTTON].xt, Buttons[gr_screen.res][HELP_BUTTON].yt, &Buttons[gr_screen.res][HELP_BUTTON].button, UI_XSTR_COLOR_GREEN); // Ui_window.add_XSTR("Options", 1036, Buttons[gr_screen.res][OPTIONS_BUTTON].xt, Buttons[gr_screen.res][OPTIONS_BUTTON].yt, &Buttons[gr_screen.res][OPTIONS_BUTTON].button, UI_XSTR_COLOR_GREEN); Ui_window.add_XSTR("Exit", 1418, Buttons[gr_screen.res][EXIT_BUTTON].xt, Buttons[gr_screen.res][EXIT_BUTTON].yt, &Buttons[gr_screen.res][EXIT_BUTTON].button, UI_XSTR_COLOR_PINK); if (Player->flags & PLAYER_FLAGS_IS_MULTI) { Buttons[gr_screen.res][SIMULATOR_TAB].button.disable(); Buttons[gr_screen.res][CUTSCENES_TAB].button.disable(); } // set some hotkeys Buttons[gr_screen.res][PREV_ENTRY_BUTTON].button.set_hotkey(KEY_LEFT); Buttons[gr_screen.res][NEXT_ENTRY_BUTTON].button.set_hotkey(KEY_RIGHT); Buttons[gr_screen.res][SCROLL_INFO_UP].button.set_hotkey(KEY_UP); Buttons[gr_screen.res][SCROLL_INFO_DOWN].button.set_hotkey(KEY_DOWN); for (i=0; i= 0) { bm_release(Weapon_list[i].bitmap); Weapon_list[i].bitmap = -1; } } delete[] Weapon_list; Weapon_list = NULL; } Weapon_list_size = 0; Weapons_loaded = 0; for (i = 0; i < Intel_list_size; i++) { if (Intel_list[i].animation != NULL) { anim_free(Intel_list[i].animation); Intel_list[i].animation = NULL; } if (Intel_list[i].bitmap >= 0) { bm_release(Intel_list[i].bitmap); Intel_list[i].bitmap = -1; } } Intel_list_size = 0; Intel_loaded = 0; } void techroom_close() { fsspeech_stop(); techroom_lists_reset(); Techroom_show_all = 0; /* if (ShipWin01){ bm_unload(ShipWin01); } if (ShipWin02){ bm_unload(ShipWin02); } if (ShipWin03){ bm_unload(ShipWin03); } if (ShipWin04){ bm_unload(ShipWin04); } */ if (Tech_background_bitmap) { bm_release(Tech_background_bitmap); } Ui_window.destroy(); common_free_interface_palette(); // restore game palette if (Palette_bmp){ bm_release(Palette_bmp); } // restore detail settings /*Detail.detail_distance = Tech_detail_backup; Detail.hardware_textures = Tech_texture_backup;*/ } void techroom_do_frame(float frametime) { int i, k; // turn off controls when overlay is on if ( help_overlay_active(TECH_ROOM_OVERLAY) ) { Buttons[gr_screen.res][HELP_BUTTON].button.reset_status(); Ui_window.set_ignore_gadgets(1); } // turn off controls in trackball mode if (Trackball_active) { Ui_window.set_ignore_gadgets(1); } else { Ui_window.set_ignore_gadgets(0); } k = Ui_window.process() & ~KEY_DEBUGGED; if ( (k > 0) || B1_JUST_RELEASED ) { if ( help_overlay_active(TECH_ROOM_OVERLAY) ) { help_overlay_set_state(TECH_ROOM_OVERLAY, 0); Ui_window.set_ignore_gadgets(0); k = 0; } } if ( !help_overlay_active(TECH_ROOM_OVERLAY) ) { Ui_window.set_ignore_gadgets(0); } switch (k) { case KEY_SHIFTED | KEY_TAB: // activate previous tab i = Tab - 1; if (i < 0) { i = NUM_TABS - 1; } techroom_change_tab(i); break; case KEY_TAB: // activate next tab i = Tab + 1; if (i >= NUM_TABS) { i = 0; } techroom_change_tab(i); break; case KEY_CTRLED | KEY_DOWN: if ( !(Player->flags & PLAYER_FLAGS_IS_MULTI) ) { techroom_button_pressed(SIMULATOR_TAB); break; } // fall through case KEY_CTRLED | KEY_UP: techroom_button_pressed(CREDITS_TAB); break; /* case KEY_UP: tech_prev_entry(); break; case KEY_DOWN: tech_next_entry(); break; */ case KEY_CTRLED | KEY_ENTER: case KEY_ESC: gameseq_post_event(GS_EVENT_MAIN_MENU); break; case KEY_CTRLED | KEY_SHIFTED | KEY_S: Techroom_show_all = 1; techroom_lists_reset(); techroom_change_tab(Tab); break; } // check ship model window for activity if (View_window.pressed()) { Trackball_active = 1; Trackball_mode = 1; } if (B1_RELEASED) { Trackball_active = 0; } // check all da buttons for (i=0; i= 0) { gr_set_bitmap(Tech_background_bitmap); gr_bitmap(0, 0); } // render switch (Tab) { case SHIPS_DATA_TAB: techroom_ships_render(frametime); /* if (ShipWin01) { gr_set_bitmap(ShipWin01); gr_bitmap(223, 104); } if (ShipWin02) { gr_set_bitmap(ShipWin02); gr_bitmap(621, 124); } if (ShipWin03) { gr_set_bitmap(ShipWin03); gr_bitmap(223, 338); } if (ShipWin04) { gr_set_bitmap(ShipWin04); gr_bitmap(218, 124); } */ break; case WEAPONS_DATA_TAB: techroom_weapons_render2(frametime); break; case INTEL_DATA_TAB: techroom_intel_render(frametime); break; } Ui_window.draw(); for (i=TECH_DATABASE_TAB; i<=CREDITS_TAB; i++) { if (Buttons[gr_screen.res][i].button.button_down()) { break; } } if (i > CREDITS_TAB) { Buttons[gr_screen.res][TECH_DATABASE_TAB].button.draw_forced(2); } for (i=0; i