1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12
13 #include <climits> // this is need even when not building debug!!
14 #include <type_traits>
15
16 #include "anim/animplay.h"
17 #include "cmdline/cmdline.h"
18 #include "cutscene/cutscenes.h"
19 #include "cutscene/movie.h"
20 #include "gamehelp/contexthelp.h"
21 #include "gamesequence/gamesequence.h"
22 #include "gamesnd/eventmusic.h"
23 #include "gamesnd/gamesnd.h"
24 #include "globalincs/linklist.h"
25 #include "graphics/2d.h"
26 #include "graphics/matrix.h"
27 #include "graphics/shadows.h"
28 #include "hud/hudwingmanstatus.h"
29 #include "io/key.h"
30 #include "io/mouse.h"
31 #include "io/timer.h"
32 #include "lighting/lighting.h"
33 #include "missionui/chatbox.h"
34 #include "missionui/missionbrief.h"
35 #include "missionui/missionscreencommon.h"
36 #include "missionui/missionshipchoice.h"
37 #include "missionui/missionweaponchoice.h"
38 #include "network/multi.h"
39 #include "network/multi_endgame.h"
40 #include "network/multimsgs.h"
41 #include "network/multiteamselect.h"
42 #include "network/multiutil.h"
43 #include "parse/sexp.h"
44 #include "popup/popup.h"
45 #include "render/3d.h"
46 #include "render/batching.h"
47 #include "scripting/scripting.h"
48 #include "ship/ship.h"
49 #include "ui/uidefs.h"
50 #include "weapon/weapon.h"
51
52 //////////////////////////////////////////////////////////////////
53 // Game Globals
54 //////////////////////////////////////////////////////////////////
55
56 int Common_select_inited = 0;
57
58 // Dependent on when mouse button goes up
59 int Drop_icon_mflag, Drop_on_wing_mflag, Brief_mouse_up_flag;
60
61 int Mouse_down_last_frame = 0;
62
63 // Timers used to flash buttons after timeouts
64 #define MSC_FLASH_AFTER_TIME 60000 // time before flashing a button
65 #define MSC_FLASH_INTERVAL 200 // time between flashes
66 int Flash_timer; // timestamp used to start flashing
67 int Flash_toggle; // timestamp used to toggle flashing
68 int Flash_bright; // state of button to flash
69
70 //////////////////////////////////////////////////////////////////
71 // Global to modulde
72 //////////////////////////////////////////////////////////////////
73 int Current_screen;
74 int Next_screen;
75 static int InterfacePaletteBitmap = -1; // PCX file that holds the interface palette
76 color Icon_colors[NUM_ICON_FRAMES];
77 shader Icon_shaders[NUM_ICON_FRAMES];
78
79 loadout_data Player_loadout; // what the ship and weapon loadout is... used since we want to use the
80 // same loadout if the mission is played again
81
82 //wss_unit Wss_slots[MAX_WSS_SLOTS]; // slot data struct
83 //int Wl_pool[MAX_WEAPON_TYPES]; // weapon pool
84 //int Ss_pool[MAX_SHIP_CLASSES]; // ship pool
85 //int Wss_num_wings; // number of player wings
86
87 wss_unit Wss_slots_teams[MAX_TVT_TEAMS][MAX_WSS_SLOTS];
88 int Wl_pool_teams[MAX_TVT_TEAMS][MAX_WEAPON_TYPES];
89 int Ss_pool_teams[MAX_TVT_TEAMS][MAX_SHIP_CLASSES];
90 int Wss_num_wings_teams[MAX_TVT_TEAMS];
91
92 wss_unit *Wss_slots = NULL;
93 int *Wl_pool = NULL;
94 int *Ss_pool = NULL;
95 int Wss_num_wings;
96
97 //////////////////////////////////////////////////////////////////
98 // Externs
99 //////////////////////////////////////////////////////////////////
100 extern void ss_set_team_pointers(int team);
101 extern void ss_reset_team_pointers();
102 extern void wl_set_team_pointers(int team);
103 extern void wl_reset_team_pointers();
104 extern int anim_timer_start;
105 extern void ss_reset_selected_ship();
106
107 //////////////////////////////////////////////////////////////////
108 // UI
109 //////////////////////////////////////////////////////////////////
110 UI_WINDOW *Active_ui_window;
111
112 brief_common_buttons Common_buttons[3][GR_NUM_RESOLUTIONS][NUM_COMMON_BUTTONS] = {
113 { // UGH
114 { // GR_640
115 brief_common_buttons("CB_00", 7, 3, 37, 7, 0),
116 brief_common_buttons("CB_01", 7, 19, 37, 23, 1),
117 brief_common_buttons("CB_02", 7, 35, 37, 39, 2),
118 brief_common_buttons("CB_05", 571, 425, 572, 413, 5),
119 brief_common_buttons("CB_06", 533, 425, 500, 440, 6),
120 brief_common_buttons("CB_07", 533, 455, 479, 464, 7),
121 },
122 { // GR_1024
123 brief_common_buttons("2_CB_00", 12, 5, 59, 12, 0),
124 brief_common_buttons("2_CB_01", 12, 31, 59, 37, 1),
125 brief_common_buttons("2_CB_02", 12, 56, 59, 62, 2),
126 brief_common_buttons("2_CB_05", 914, 681, 937, 671, 5),
127 brief_common_buttons("2_CB_06", 854, 681, 822, 704, 6),
128 brief_common_buttons("2_CB_07", 854, 724, 800, 743, 7),
129 }
130 },
131 { // UGH
132 { // GR_640
133 brief_common_buttons("CB_00", 7, 3, 37, 7, 0),
134 brief_common_buttons("CB_01", 7, 19, 37, 23, 1),
135 brief_common_buttons("CB_02", 7, 35, 37, 39, 2),
136 brief_common_buttons("CB_05", 571, 425, 572, 413, 5),
137 brief_common_buttons("CB_06", 533, 425, 500, 440, 6),
138 brief_common_buttons("CB_07", 533, 455, 479, 464, 7),
139 },
140 { // GR_1024
141 brief_common_buttons("2_CB_00", 12, 5, 59, 12, 0),
142 brief_common_buttons("2_CB_01", 12, 31, 59, 37, 1),
143 brief_common_buttons("2_CB_02", 12, 56, 59, 62, 2),
144 brief_common_buttons("2_CB_05", 914, 681, 937, 671, 5),
145 brief_common_buttons("2_CB_06", 854, 681, 822, 704, 6),
146 brief_common_buttons("2_CB_07", 854, 724, 800, 743, 7),
147 }
148 },
149 { // UGH
150 { // GR_640
151 brief_common_buttons("CB_00", 7, 3, 37, 7, 0),
152 brief_common_buttons("CB_01", 7, 19, 37, 23, 1),
153 brief_common_buttons("CB_02", 7, 35, 37, 39, 2),
154 brief_common_buttons("CB_05", 571, 425, 572, 413, 5),
155 brief_common_buttons("CB_06", 533, 425, 500, 440, 6),
156 brief_common_buttons("CB_07", 533, 455, 479, 464, 7),
157 },
158 { // GR_1024
159 brief_common_buttons("2_CB_00", 12, 5, 59, 12, 0),
160 brief_common_buttons("2_CB_01", 12, 31, 59, 37, 1),
161 brief_common_buttons("2_CB_02", 12, 56, 59, 62, 2),
162 brief_common_buttons("2_CB_05", 914, 681, 937, 671, 5),
163 brief_common_buttons("2_CB_06", 854, 681, 822, 704, 6),
164 brief_common_buttons("2_CB_07", 854, 724, 800, 743, 7),
165 }
166 }
167 };
168
169 #define COMMON_BRIEFING_BUTTON 0
170 #define COMMON_SS_BUTTON 1
171 #define COMMON_WEAPON_BUTTON 2
172 #define COMMON_COMMIT_BUTTON 3
173 #define COMMON_HELP_BUTTON 4
174 #define COMMON_OPTIONS_BUTTON 5
175
176 int Background_playing; // Flag to indicate background animation is playing
177 static anim *Background_anim; // Ids for the anim data that is loaded
178
179 // value for which Team_data entry to use
180 int Common_team;
181
182 // Ids for the instance of the anim that is playing
183 //static anim_instance *Background_anim_instance;
184
185 int Wing_slot_empty_bitmap;
186 int Wing_slot_disabled_bitmap;
187
188 // prototypes
189 int wss_slots_all_empty();
190
191 // Display the no ships selected error
common_show_no_ship_error()192 void common_show_no_ship_error()
193 {
194 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "At least one ship must be selected before proceeding to weapons loadout", 460));
195 }
196
197 // Check the status of the buttons common to the loadout screens
common_check_buttons()198 void common_check_buttons()
199 {
200 int i;
201 UI_BUTTON *b;
202
203 for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
204 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
205 if ( b->pressed() ) {
206
207 common_button_do(i);
208 }
209 }
210
211 /*
212 // AL 11-23-97: let a joystick button press commit
213 if ( joy_down_count(0) || joy_down_count(1) ) {
214 Commit_pressed = 1;
215 }
216 */
217
218 }
219
220 // -------------------------------------------------------------------
221 // common_redraw_pressed_buttons()
222 //
223 // Redraw any common buttons that are pressed down. This function is needed
224 // since we sometimes need to draw pressed buttons last to ensure the entire
225 // button gets drawn (and not overlapped by other buttons)
226 //
common_redraw_pressed_buttons()227 void common_redraw_pressed_buttons()
228 {
229 int i;
230 UI_BUTTON *b;
231
232 for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
233 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
234 if ( b->button_down() ) {
235 b->draw_forced(2);
236 }
237 }
238 }
239
common_buttons_maybe_reload(UI_WINDOW *)240 void common_buttons_maybe_reload(UI_WINDOW * /*ui_window*/)
241 {
242 UI_BUTTON *b;
243 int i;
244
245 for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
246 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
247 b->set_bmaps(Common_buttons[Current_screen-1][gr_screen.res][i].filename);
248 }
249 }
250
common_buttons_init(UI_WINDOW * ui_window)251 void common_buttons_init(UI_WINDOW *ui_window)
252 {
253 UI_BUTTON *b;
254 int i;
255
256 for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
257 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
258 b->create( ui_window, "", Common_buttons[Current_screen-1][gr_screen.res][i].x, Common_buttons[Current_screen-1][gr_screen.res][i].y, 60, 30, 0, 1);
259 // set up callback for when a mouse first goes over a button
260 b->set_highlight_action( common_play_highlight_sound );
261 b->set_bmaps(Common_buttons[Current_screen-1][gr_screen.res][i].filename);
262 b->link_hotspot(Common_buttons[Current_screen-1][gr_screen.res][i].hotspot);
263 }
264
265 // add some text
266 ui_window->add_XSTR("Briefing", 1504, Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_BUTTON].button, UI_XSTR_COLOR_GREEN);
267 ui_window->add_XSTR("Ship Selection", 1067, Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_BUTTON].button, UI_XSTR_COLOR_GREEN);
268 ui_window->add_XSTR("Weapon Loadout", 1068, Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_BUTTON].button, UI_XSTR_COLOR_GREEN);
269 ui_window->add_XSTR("Commit", 1062, Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].button, UI_XSTR_COLOR_PINK);
270 ui_window->add_XSTR("Help", 928, Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].button, UI_XSTR_COLOR_GREEN);
271 ui_window->add_XSTR("Options", 1036, Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].xt, Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].yt, &Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].button, UI_XSTR_COLOR_GREEN);
272
273 common_reset_buttons();
274
275 Common_buttons[Current_screen-1][gr_screen.res][COMMON_COMMIT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
276 Common_buttons[Current_screen-1][gr_screen.res][COMMON_HELP_BUTTON].button.set_hotkey(KEY_F1);
277 Common_buttons[Current_screen-1][gr_screen.res][COMMON_OPTIONS_BUTTON].button.set_hotkey(KEY_F2);
278
279 // for scramble or training missions, disable the ship/weapon selection regions
280 if ( brief_only_allow_briefing() ) {
281 Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_REGION].button.disable();
282 Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_REGION].button.disable();
283 }
284 }
285
286 // Try to load background bitmaps as appropriate
mission_ui_background_load(const char * custom_background,const char * single_background,const char * multi_background)287 int mission_ui_background_load(const char *custom_background, const char *single_background, const char *multi_background)
288 {
289 int background_bitmap = -1;
290
291 if (custom_background && (*custom_background != '\0'))
292 {
293 background_bitmap = bm_load(custom_background);
294 if (background_bitmap < 0)
295 mprintf(("Failed to load custom background bitmap %s!\n", custom_background));
296 }
297
298 // if special background failed to load, or if no special background was supplied, load the standard bitmap
299 if (background_bitmap < 0)
300 {
301 if (multi_background && (Game_mode & GM_MULTIPLAYER))
302 background_bitmap = bm_load(multi_background);
303 else
304 background_bitmap = bm_load(single_background);
305 }
306
307 // return what we've got
308 return background_bitmap;
309 }
310
set_active_ui(UI_WINDOW * ui_window)311 void set_active_ui(UI_WINDOW *ui_window)
312 {
313 Active_ui_window = ui_window;
314 }
315
common_music_get_filename(int score_index)316 SCP_string common_music_get_filename(int score_index)
317 {
318 if (Cmdline_freespace_no_music) {
319 return SCP_string();
320 }
321
322 Assertion(score_index >= 0 && score_index < NUM_SCORES, "Invalid score index %d.", score_index);
323
324 if (Mission_music[score_index] < 0) {
325 if (Num_music_files > 0) {
326 Mission_music[score_index] = 0;
327 nprintf(("Sound",
328 "No briefing music is selected, so play first briefing track: %s\n",
329 Spooled_music[Mission_music[score_index]].name));
330 } else {
331 return SCP_string();
332 }
333 }
334
335 return Spooled_music[Mission_music[score_index]].filename;
336 }
337
common_music_init(int score_index)338 void common_music_init(int score_index)
339 {
340 const auto file_name = common_music_get_filename(score_index);
341
342 if (file_name.empty()) {
343 return;
344 }
345
346 briefing_load_music(file_name.c_str());
347 // Use this id to trigger the start of music playing on the briefing screen
348 Briefing_music_begin_timestamp = timestamp(BRIEFING_MUSIC_DELAY);
349 }
350
common_music_do()351 void common_music_do()
352 {
353 if ( Cmdline_freespace_no_music ) {
354 return;
355 }
356
357 // Use this id to trigger the start of music playing on the briefing screen
358 if ( timestamp_elapsed( Briefing_music_begin_timestamp) ) {
359 Briefing_music_begin_timestamp = 0;
360 briefing_start_music();
361 }
362 }
363
common_music_close()364 void common_music_close()
365 {
366 if ( Cmdline_freespace_no_music ) {
367 return;
368 }
369
370 if ( Num_music_files <= 0 )
371 return;
372
373 briefing_stop_music(true);
374 }
375
common_num_cutscenes_valid(int movie_type)376 int common_num_cutscenes_valid(int movie_type)
377 {
378 int num_valid_cutscenes = 0;
379
380 for (uint i = 0; i < The_mission.cutscenes.size(); i++) {
381 if (movie_type == The_mission.cutscenes[i].type) {
382 if (!eval_sexp( The_mission.cutscenes[i].formula )) {
383 continue;
384 }
385
386 num_valid_cutscenes++;
387 }
388 }
389
390 return num_valid_cutscenes;
391 }
392
common_maybe_play_cutscene(int movie_type,bool restart_music,int music)393 void common_maybe_play_cutscene(int movie_type, bool restart_music, int music)
394 {
395 bool music_off = false;
396
397 for (uint i = 0; i < The_mission.cutscenes.size(); i++) {
398 if (movie_type == The_mission.cutscenes[i].type) {
399 if (!eval_sexp( The_mission.cutscenes[i].formula )) {
400 continue;
401 }
402
403 if ( strlen(The_mission.cutscenes[i].filename) ) {
404 common_music_close();
405 music_off = true;
406 movie::play(The_mission.cutscenes[i].filename); //Play the movie!
407 cutscene_mark_viewable( The_mission.cutscenes[i].filename );
408 }
409 }
410 }
411
412 if (music_off && restart_music) {
413 common_music_init(music);
414 }
415 }
416
417 // function that sets the current palette to the interface palette. This function
418 // needs to be followed by common_free_interface_palette() to restore the game palette.
common_set_interface_palette(const char * filename)419 void common_set_interface_palette(const char *filename)
420 {
421 static char buf[MAX_FILENAME_LEN + 1] = {0};
422
423 if (!filename)
424 filename = NOX("palette01");
425
426 Assert(strlen(filename) <= MAX_FILENAME_LEN);
427 if ( (InterfacePaletteBitmap != -1) && !stricmp(filename, buf) )
428 return; // already set to this palette
429
430 strcpy_s(buf, filename);
431
432 // unload the interface bitmap from memory
433 if (InterfacePaletteBitmap != -1) {
434 bm_release(InterfacePaletteBitmap);
435 InterfacePaletteBitmap = -1;
436 }
437
438 // ugh - we don't need this anymore
439 /*
440 InterfacePaletteBitmap = bm_load(filename);
441 if (InterfacePaletteBitmap < 0) {
442 Error(LOCATION, "Could not load in \"%s\"!", filename);
443 }
444 */
445 }
446
447 // release the interface palette .pcx file, and restore the game palette
common_free_interface_palette()448 void common_free_interface_palette()
449 {
450 // unload the interface bitmap from memory
451 if (InterfacePaletteBitmap != -1) {
452 bm_release(InterfacePaletteBitmap);
453 InterfacePaletteBitmap = -1;
454 }
455 }
456
457 // Init timers used for flashing buttons
common_flash_button_init()458 void common_flash_button_init()
459 {
460 Flash_timer = timestamp(MSC_FLASH_AFTER_TIME);
461 Flash_toggle = 1;
462 Flash_bright = 0;
463 }
464
465 // determine if we should draw a button as bright
common_flash_bright()466 int common_flash_bright()
467 {
468 if ( timestamp_elapsed(Flash_timer) ) {
469 if ( timestamp_elapsed(Flash_toggle) ) {
470 Flash_toggle = timestamp(MSC_FLASH_INTERVAL);
471 Flash_bright ^= 1;
472 }
473 }
474
475 return Flash_bright;
476 }
477
478 // set the necessary pointers
common_set_team_pointers(int team)479 void common_set_team_pointers(int team)
480 {
481 Assert( (team >= 0) && (team < MAX_TVT_TEAMS) );
482
483 Wss_slots = Wss_slots_teams[team];
484 Ss_pool = Ss_pool_teams[team];
485 Wl_pool = Wl_pool_teams[team];
486
487 ss_set_team_pointers(team);
488 wl_set_team_pointers(team);
489 }
490
491 // reset the necessary pointers to defaults
common_reset_team_pointers()492 void common_reset_team_pointers()
493 {
494 ss_reset_team_pointers();
495 wl_reset_team_pointers();
496
497 // these are done last so that we can make use of the Assert()'s in the above
498 // functions to make sure the screens are exited and this is safe
499 Wss_slots = NULL;
500 Ss_pool = NULL;
501 Wl_pool = NULL;
502 }
503
504 // common_select_init() will load in animations and bitmaps that are common to the
505 // briefing/ship select/weapon select screens. The global Common_select_inited is set
506 // after this function is called once, and is only cleared when common_select_close()
507 // is called. This prevents multiple loadings of animations/bitmaps.
508 //
509 // This function also sets the palette based on the file palette01.pcx
common_select_init()510 void common_select_init()
511 {
512 if ( Common_select_inited ) {
513 nprintf(("Alan","common_select_init() returning without doing anything\n"));
514 return;
515 }
516
517 nprintf(("Alan","entering common_select_init()\n"));
518
519 // No anims are playing
520 Background_playing = 0;
521 Background_anim = NULL;
522
523 Current_screen = Next_screen = ON_BRIEFING_SELECT;
524
525 // load in the icons for the wing slots
526 load_wing_icons(NOX("iconwing01"));
527
528 Current_screen = Next_screen = ON_BRIEFING_SELECT;
529
530 Commit_pressed = 0;
531
532 Common_select_inited = 1;
533
534 // this handles the case where the player played a multiplayer game but now is in single player (in one instance
535 // of FreeSpace)
536 if(!(Game_mode & GM_MULTIPLAYER)){
537 chatbox_close();
538 }
539
540 // get the value of the team
541 Common_team = 0; // assume the first team -- we'll change this value if we need to
542
543 if ( (Game_mode & GM_MULTIPLAYER) && IS_MISSION_MULTI_TEAMS )
544 Common_team = Net_player->p_info.team;
545
546 common_set_team_pointers(Common_team);
547
548 ship_select_common_init();
549 weapon_select_common_init();
550 common_flash_button_init();
551
552 if ( Game_mode & GM_MULTIPLAYER ) {
553 multi_ts_common_init();
554 }
555
556 // restore loadout from Player_loadout if this is the same mission as the one previously played
557 if ( !(Game_mode & GM_MULTIPLAYER) ) {
558 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
559 wss_maybe_restore_loadout();
560 ss_synch_interface();
561 wl_synch_interface();
562 }
563 }
564
565 ss_reset_selected_ship();
566
567 Drop_icon_mflag = 0;
568 Drop_on_wing_mflag = 0;
569
570 //init colors
571 gr_init_alphacolor(&Icon_colors[ICON_FRAME_NORMAL], 32, 128, 128, 255);
572 gr_init_alphacolor(&Icon_colors[ICON_FRAME_HOT], 48, 160, 160, 255);
573 gr_init_alphacolor(&Icon_colors[ICON_FRAME_SELECTED], 64, 192, 192, 255);
574 gr_init_alphacolor(&Icon_colors[ICON_FRAME_PLAYER], 192, 128, 64, 255);
575 gr_init_alphacolor(&Icon_colors[ICON_FRAME_DISABLED], 175, 175, 175, 255);
576 gr_init_alphacolor(&Icon_colors[ICON_FRAME_DISABLED_HIGH], 100, 100, 100, 255);
577 //init shaders
578 gr_create_shader(&Icon_shaders[ICON_FRAME_NORMAL], 32, 128, 128, 255);
579 gr_create_shader(&Icon_shaders[ICON_FRAME_HOT], 48, 160, 160, 255);
580 gr_create_shader(&Icon_shaders[ICON_FRAME_SELECTED], 64, 192, 192, 255);
581 gr_create_shader(&Icon_shaders[ICON_FRAME_PLAYER], 192, 128, 64, 255);
582 gr_create_shader(&Icon_shaders[ICON_FRAME_DISABLED], 175, 175, 175, 255);
583 gr_create_shader(&Icon_shaders[ICON_FRAME_DISABLED_HIGH], 100, 100, 100, 255);
584 }
585
common_reset_buttons()586 void common_reset_buttons()
587 {
588 int i;
589 UI_BUTTON *b;
590
591 for ( i = 0; i < NUM_COMMON_BUTTONS; i++ ) {
592 b = &Common_buttons[Current_screen-1][gr_screen.res][i].button;
593 b->reset_status();
594 }
595
596 switch(Current_screen) {
597 case ON_BRIEFING_SELECT:
598 Common_buttons[Current_screen-1][gr_screen.res][COMMON_BRIEFING_REGION].button.skip_first_highlight_callback();
599 break;
600 case ON_SHIP_SELECT:
601 Common_buttons[Current_screen-1][gr_screen.res][COMMON_SS_REGION].button.skip_first_highlight_callback();
602 break;
603 case ON_WEAPON_SELECT:
604 Common_buttons[Current_screen-1][gr_screen.res][COMMON_WEAPON_REGION].button.skip_first_highlight_callback();
605 break;
606 }
607 }
608
609 // common_select_do() is called once per loop in the interface screens and is used
610 // for drawing and changing the common animations and blitting common bitmaps.
common_select_do(float)611 int common_select_do(float /*frametime*/)
612 {
613 int k, new_k;
614
615
616 if ( help_overlay_active(Briefing_overlay_id) || help_overlay_active(Ship_select_overlay_id) || help_overlay_active(Weapon_select_overlay_id) ) {
617 Common_buttons[0][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
618 Common_buttons[1][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
619 Common_buttons[2][gr_screen.res][COMMON_HELP_BUTTON].button.reset_status();
620 Active_ui_window->set_ignore_gadgets(1);
621 } else {
622 Active_ui_window->set_ignore_gadgets(0);
623 }
624
625 k = chatbox_process();
626
627 if ( Game_mode & GM_NORMAL ) {
628 new_k = Active_ui_window->process(k);
629 } else {
630 new_k = Active_ui_window->process(k, 0);
631 }
632
633 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
634 if ( help_overlay_active(Briefing_overlay_id) || help_overlay_active(Ship_select_overlay_id) || help_overlay_active(Weapon_select_overlay_id) ) {
635 help_overlay_set_state(Briefing_overlay_id, gr_screen.res, 0);
636 help_overlay_set_state(Ship_select_overlay_id, gr_screen.res, 0);
637 help_overlay_set_state(Weapon_select_overlay_id, gr_screen.res, 0);
638 Active_ui_window->set_ignore_gadgets(0);
639 k = 0;
640 new_k = 0;
641 }
642 }
643
644 // test for mouse buttons, must be done after Active_ui_window->process()
645 // has been called to work properly
646 //
647 Drop_icon_mflag = 0;
648 Drop_on_wing_mflag = 0;
649 Brief_mouse_up_flag = 0;
650 Mouse_down_last_frame = 0;
651
652 // if the left mouse button was released...
653 if ( B1_RELEASED ) {
654 Drop_icon_mflag = 1;
655 Drop_on_wing_mflag = 1;
656 }
657
658 // if the left mouse button was pressed...
659 if ( B1_PRESSED ) {
660 Mouse_down_last_frame = 1;
661 }
662
663 // basically a "click", only check for the click here to avoid action-on-over on briefing map
664 if ( B1_JUST_PRESSED ) {
665 Brief_mouse_up_flag = 1;
666 }
667
668 // reset timers for flashing buttons if key pressed
669 if ( (k>0) || (new_k>0) ) {
670 common_flash_button_init();
671 }
672
673 common_music_do();
674
675 /*
676 if ( Background_playing ) {
677
678 if ( Background_anim_instance->frame_num == BUTTON_SLIDE_IN_FRAME ) {
679 gamesnd_play_iface(SND_BTN_SLIDE);
680 }
681
682 if ( Background_anim_instance->frame_num == Background_anim_instance->stop_at ) {
683 // Free up the big honking background animation, since we won't be playing it again
684 anim_release_render_instance(Background_anim_instance);
685 anim_free(Background_anim);
686
687 Background_playing = 0;
688 Current_screen = Next_screen = ON_BRIEFING_SELECT;
689 }
690 }
691 */
692
693 if ( Current_screen != Next_screen ) {
694 switch( Next_screen ) {
695 case ON_BRIEFING_SELECT:
696 gameseq_post_event( GS_EVENT_START_BRIEFING );
697 break;
698
699 case ON_SHIP_SELECT:
700 // go to the specialized multiplayer team/ship select screen
701 if(Game_mode & GM_MULTIPLAYER){
702 gameseq_post_event(GS_EVENT_TEAM_SELECT);
703 }
704 // go to the normal ship select screen
705 else {
706 gameseq_post_event(GS_EVENT_SHIP_SELECTION);
707 }
708 break;
709
710 case ON_WEAPON_SELECT:
711 if ( !wss_slots_all_empty() ) {
712 gameseq_post_event(GS_EVENT_WEAPON_SELECTION);
713 } else {
714 common_show_no_ship_error();
715 }
716 break;
717 } // end switch
718 }
719
720 return new_k;
721 }
722
723 // -------------------------------------------------------------------------------------
724 // common_render()
725 //
common_render(float frametime)726 void common_render(float frametime)
727 {
728 if ( !Background_playing ) {
729 GR_MAYBE_CLEAR_RES(Brief_background_bitmap);
730 gr_set_bitmap(Brief_background_bitmap);
731 gr_bitmap(0, 0, GR_RESIZE_MENU);
732 }
733
734 anim_render_all(0, frametime);
735 anim_render_all(ON_SHIP_SELECT, frametime);
736 }
737
738 // -------------------------------------------------------------------------------------
739 // common_render_selected_screen_button()
740 //
741 // A very ugly piece of special purpose code. This is used to draw the pressed button
742 // frame for whatever stage of the briefing/ship select/weapons loadout we are on.
743 //
common_render_selected_screen_button()744 void common_render_selected_screen_button()
745 {
746 Common_buttons[Next_screen-1][gr_screen.res][Next_screen-1].button.draw_forced(2);
747 }
748
749 // -------------------------------------------------------------------------------------
750 // common_button_do() do the button action for the specified pressed button
751 //
common_button_do(int i)752 void common_button_do(int i)
753 {
754 if ( i == COMMON_COMMIT_BUTTON ) {
755 Commit_pressed = 1;
756 return;
757 }
758
759 if ( Background_playing )
760 return;
761
762 switch ( i ) {
763
764 case COMMON_BRIEFING_BUTTON:
765 if ( Current_screen != ON_BRIEFING_SELECT ) {
766 gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
767 Next_screen = ON_BRIEFING_SELECT;
768 }
769 break;
770
771 case COMMON_WEAPON_BUTTON:
772 if ( Current_screen != ON_WEAPON_SELECT ) {
773 if ( !wss_slots_all_empty() ) {
774 gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
775 Next_screen = ON_WEAPON_SELECT;
776 } else {
777 common_show_no_ship_error();
778 }
779 }
780 break;
781
782 case COMMON_SS_BUTTON:
783 if ( Current_screen != ON_SHIP_SELECT ) {
784 gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
785 Next_screen = ON_SHIP_SELECT;
786 }
787 break;
788
789 case COMMON_OPTIONS_BUTTON:
790 gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
791 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
792 break;
793
794 case COMMON_HELP_BUTTON:
795 gamesnd_play_iface(InterfaceSounds::HELP_PRESSED);
796 launch_context_help();
797 break;
798
799 } // end switch
800 }
801
802 // common_check_keys() will check for keypresses common to all the interface screens.
common_check_keys(int k)803 void common_check_keys(int k)
804 {
805 switch (k) {
806
807 case KEY_ESC: {
808
809 if ( Current_screen == ON_BRIEFING_SELECT ) {
810 if ( brief_get_closeup_icon() != NULL ) {
811 brief_turn_off_closeup_icon();
812 break;
813 }
814 }
815
816 // prompt the host of a multiplayer game
817 if(Game_mode & GM_MULTIPLAYER){
818 multi_quit_game(PROMPT_ALL);
819 } else {
820 // go through the single player quit process
821 // return to the main menu
822 /*
823 int return_to_menu, pf_flags;
824 pf_flags = PF_USE_AFFIRMATIVE_ICON|PF_USE_NEGATIVE_ICON;
825 return_to_menu = popup(pf_flags, 2, POPUP_NO, POPUP_YES, XSTR( "Do you want to return to the Main Hall?\n(Your campaign position will be saved)", -1));
826 if ( return_to_menu == 1 ) {
827 gameseq_post_event(GS_EVENT_MAIN_MENU);
828 }
829 */
830 gameseq_post_event(GS_EVENT_MAIN_MENU);
831 }
832 break;
833 }
834
835 case KEY_CTRLED + KEY_ENTER:
836 Commit_pressed = 1;
837 break;
838
839 case KEY_B:
840 if ( Current_screen != ON_BRIEFING_SELECT && !Background_playing ) {
841 Next_screen = ON_BRIEFING_SELECT;
842 }
843 break;
844
845 case KEY_W:
846 if ( brief_only_allow_briefing() ) {
847 gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
848 break;
849 }
850
851 if ( Current_screen != ON_WEAPON_SELECT && !Background_playing ) {
852 if ( !wss_slots_all_empty() ) {
853 Next_screen = ON_WEAPON_SELECT;
854 } else {
855 common_show_no_ship_error();
856 }
857 }
858
859 break;
860
861 case KEY_S:
862
863 if ( brief_only_allow_briefing() ) {
864 gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
865 break;
866 }
867
868 if ( Current_screen != ON_SHIP_SELECT && !Background_playing ) {
869 Next_screen = ON_SHIP_SELECT;
870 }
871
872 break;
873
874 case KEY_SHIFTED+KEY_TAB:
875
876 if ( brief_only_allow_briefing() ) {
877 gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
878 break;
879 }
880
881 if ( !Background_playing ) {
882 switch ( Current_screen ) {
883 case ON_BRIEFING_SELECT:
884 if ( !wss_slots_all_empty() ) {
885 Next_screen = ON_WEAPON_SELECT;
886 } else {
887 common_show_no_ship_error();
888 }
889 break;
890
891 case ON_SHIP_SELECT:
892 Next_screen = ON_BRIEFING_SELECT;
893 break;
894
895 case ON_WEAPON_SELECT:
896 Next_screen = ON_SHIP_SELECT;
897 break;
898 default:
899 Int3();
900 break;
901 } // end switch
902 }
903
904 break;
905
906 case KEY_TAB:
907
908 if ( brief_only_allow_briefing() ) {
909 gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
910 break;
911 }
912
913 if ( !Background_playing ) {
914 switch ( Current_screen ) {
915 case ON_BRIEFING_SELECT:
916 Next_screen = ON_SHIP_SELECT;
917 break;
918
919 case ON_SHIP_SELECT:
920 if ( !wss_slots_all_empty() ) {
921 Next_screen = ON_WEAPON_SELECT;
922 } else {
923 common_show_no_ship_error();
924 }
925 break;
926
927 case ON_WEAPON_SELECT:
928 Next_screen = ON_BRIEFING_SELECT;
929 break;
930 default:
931 Int3();
932 break;
933 } // end switch
934 }
935
936 break;
937
938 case KEY_P:
939 if ( Anim_paused )
940 Anim_paused = 0;
941 else
942 Anim_paused = 1;
943 break;
944 } // end switch
945 }
946
947 // common_select_close() will release the memory for animations and bitmaps that
948 // were loaded in common_select_init(). This function will abort if the Common_select_inited
949 // flag is not set. The last thing common_select_close() does in clear the Common_select_inited
950 // flag.
951 //
952 // weapon_select_close() and ship_select_close() are both called, since common_select_close()
953 // is the function that is called the interface screens are finally exited.
common_select_close()954 void common_select_close()
955 {
956 if ( !Common_select_inited ) {
957 nprintf(("Alan","common_select_close() returning without doing anything\n"));
958 return;
959 }
960
961 nprintf(("Alan","entering common_select_close()\n"));
962
963 // catch open anims that weapon_select_init_team() opened when not in weapon_select - taylor
964 // *** not the same as weapon_select_close() ***
965 weapon_select_close_team();
966
967 weapon_select_close();
968
969 if(Game_mode & GM_MULTIPLAYER){
970 multi_ts_close();
971 }
972
973 ship_select_close();
974 brief_close();
975
976 common_free_interface_palette();
977
978 // release the bitmpas that were previously extracted from anim files
979 unload_wing_icons();
980
981 // Release any instances that may still exist
982 anim_release_all_instances();
983
984 // free the anim's that were loaded into memory
985 /*
986 if ( Background_anim ) {
987 anim_free(Background_anim);
988 Background_anim = NULL;
989 }
990 */
991
992 common_music_close();
993
994 common_reset_team_pointers();
995
996 Common_select_inited = 0;
997 }
998
999 // ------------------------------------------------------------------------
1000 // load_wing_icons() creates the bitmaps for wing icons
1001 //
load_wing_icons(const char * filename)1002 void load_wing_icons(const char *filename)
1003 {
1004 int first_frame, num_frames;
1005
1006 first_frame = bm_load_animation(filename, &num_frames);
1007 if ( first_frame == -1 ) {
1008 Error(LOCATION, "Could not load icons from %s\n", filename);
1009 return;
1010 }
1011
1012 Wing_slot_disabled_bitmap = first_frame;
1013 Wing_slot_empty_bitmap = first_frame + 1;
1014 // Wing_slot_player_empty_bitmap = first_frame + 2;
1015 }
1016
1017 // ------------------------------------------------------------------------
1018 // common_scroll_up_pressed()
1019 //
common_scroll_up_pressed(int * start,int size,int max_show)1020 int common_scroll_up_pressed(int *start, int size, int max_show)
1021 {
1022 // check if we even need to scroll at all
1023 if ( size <= max_show ) {
1024 return 0;
1025 }
1026
1027 if ( (size - *start) > max_show ) {
1028 *start += 1;
1029 return 1;
1030 }
1031 return 0;
1032 }
1033
1034 // ------------------------------------------------------------------------
1035 // common_scroll_down_pressed()
1036 //
common_scroll_down_pressed(int * start,int size,int max_show)1037 int common_scroll_down_pressed(int *start, int size, int max_show)
1038 {
1039 // check if we even need to scroll at all
1040 if ( size <= max_show ) {
1041 return 0;
1042 }
1043
1044 if ( *start > 0 ) {
1045 *start -= 1;
1046 return 1;
1047 }
1048 return 0;
1049 }
1050
common_fire_stage_script_hook(int old_stage,int new_stage)1051 void common_fire_stage_script_hook(int old_stage, int new_stage)
1052 {
1053 if (!Script_system.IsActiveAction(CHA_ONBRIEFSTAGE)) {
1054 return;
1055 }
1056 // call a scripting hook for switching stages
1057 // note that we add 1 because Lua arrays are 1-based
1058 Script_system.SetHookVar("OldStage", 'i', old_stage + 1);
1059 Script_system.SetHookVar("NewStage", 'i', new_stage + 1);
1060 Script_system.RunCondition(CHA_ONBRIEFSTAGE);
1061 Script_system.RemHookVars({"OldStage", "NewStage"});
1062 }
1063
1064 // NEWSTUFF BEGIN
1065
1066 // save ship selection loadout to the Player_loadout struct
wss_save_loadout()1067 void wss_save_loadout()
1068 {
1069 int i,j;
1070
1071 Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) );
1072
1073 // save the ship pool
1074 for ( i = 0; i < MAX_SHIP_CLASSES; i++ ) {
1075 Player_loadout.ship_pool[i] = Ss_pool[i];
1076 }
1077
1078 // save the weapons pool
1079 for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
1080 Player_loadout.weapon_pool[i] = Wl_pool[i];
1081 }
1082
1083 // save the ship class / weapons for each slot
1084 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1085 Player_loadout.unit_data[i].ship_class = Wss_slots[i].ship_class;
1086
1087 for ( j = 0; j < MAX_SHIP_WEAPONS; j++ ) {
1088 Player_loadout.unit_data[i].wep[j] = Wss_slots[i].wep[j];
1089 Player_loadout.unit_data[i].wep_count[j] = Wss_slots[i].wep_count[j];
1090 }
1091 }
1092 }
1093
1094 // restore ship/weapons loadout from the Player_loadout struct
wss_maybe_restore_loadout()1095 void wss_maybe_restore_loadout()
1096 {
1097 int i,j;
1098 wss_unit *slot;
1099
1100 Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) );
1101
1102 // only restore if mission hasn't changed
1103 if ( stricmp(Player_loadout.last_modified, The_mission.modified) != 0 ) {
1104 return;
1105 }
1106
1107 // first we generate a pool of ships and weapons used the last time this mission was played. We also generate a pool of what is
1108 // available in this mission.
1109 int last_loadout_ships[MAX_SHIP_CLASSES];
1110 int this_loadout_ships[MAX_SHIP_CLASSES];
1111
1112 int last_loadout_weapons[MAX_WEAPON_TYPES];
1113 int this_loadout_weapons[MAX_WEAPON_TYPES];
1114
1115 // zero all pools
1116 for (i = 0; i < MAX_SHIP_CLASSES; i++) {
1117 last_loadout_ships[i] = 0;
1118 this_loadout_ships[i] = 0;
1119 }
1120 for (i = 0; i < MAX_WEAPON_TYPES; i++) {
1121 last_loadout_weapons[i] = 0;
1122 this_loadout_weapons[i] = 0;
1123 }
1124
1125 // record the ship classes / weapons used last time
1126 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1127 slot = &Player_loadout.unit_data[i];
1128 if ((slot->ship_class >= 0) && (slot->ship_class < ship_info_size())) {
1129 ++last_loadout_ships[slot->ship_class];
1130
1131 for ( j = 0; j < MAX_SHIP_WEAPONS; j++ ) {
1132 if ((slot->wep[j] >= 0) && (slot->wep[j] < weapon_info_size())) {
1133 last_loadout_weapons[slot->wep[j]] += slot->wep_count[j];
1134 }
1135 }
1136 }
1137 }
1138
1139 // record the ships classes / weapons used by the player and wingmen. We don't include the amount in the pools yet
1140 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1141 if ((Wss_slots[i].ship_class >= 0) && (Wss_slots[i].ship_class < ship_info_size())) {
1142 ++this_loadout_ships[Wss_slots[i].ship_class];
1143
1144 for ( j = 0; j < MAX_SHIP_WEAPONS; j++ ) {
1145 if ((Wss_slots[i].wep[j] >= 0) && (Wss_slots[i].wep[j] < weapon_info_size())) {
1146 this_loadout_weapons[Wss_slots[i].wep[j]] += Wss_slots[i].wep_count[j];
1147 }
1148 }
1149 }
1150 }
1151
1152 // now compare the two, adding in what was left in the pools. If there are less of a ship or weapon class in the mission now
1153 // than there were last time, we can't restore and must abort.
1154 for (i = 0; i < ship_info_size(); i++) {
1155 if (Ss_pool[i] >= 1) {
1156 this_loadout_ships[i] += Ss_pool[i];
1157 }
1158 if ( this_loadout_ships[i] < last_loadout_ships[i]) {
1159 return;
1160 }
1161 }
1162
1163 for (i = 0; i < weapon_info_size(); i++) {
1164 if (Wl_pool[i] >= 1) {
1165 this_loadout_weapons[i] += Wl_pool[i];
1166 }
1167 if ( this_loadout_weapons[i] < last_loadout_weapons[i]) {
1168 return;
1169 }
1170 }
1171
1172 // go through the slots and restore the previous runthrough's loadout. Also remove that ship from total of ships in this mission
1173 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1174 slot = &Player_loadout.unit_data[i];
1175
1176 if ((slot->ship_class >= 0) && (slot->ship_class < ship_info_size())) {
1177 --this_loadout_ships[slot->ship_class];
1178 Assertion((this_loadout_ships[slot->ship_class] >= 0), "Attempting to restore the previous missions loadout has resulted in an invalid number of ships available");
1179
1180 }
1181 // restore the ship class for each slot
1182 Wss_slots[i].ship_class = slot->ship_class;
1183
1184 for ( j = 0; j < MAX_SHIP_WEAPONS; j++ ) {
1185 if ((slot->ship_class >= 0) && (slot->wep[j] >= 0) && (slot->wep[j] < weapon_info_size())) {
1186 this_loadout_weapons[slot->wep[j]] -= slot->wep_count[j];
1187 Assertion((this_loadout_weapons[slot->wep[j]] >= 0), "Attempting to restore the previous missions loadout has resulted in an invalid number of weapons available");
1188 }
1189
1190 Wss_slots[i].wep[j]= slot->wep[j];
1191 Wss_slots[i].wep_count[j] = slot->wep_count[j];
1192 }
1193 }
1194
1195 // restore the ship pool
1196 for ( i = 0; i < ship_info_size(); i++ ) {
1197 Ss_pool[i] = this_loadout_ships[i];
1198 }
1199
1200 // restore the weapons pool
1201 for ( i = 0; i < weapon_info_size(); i++ ) {
1202 Wl_pool[i] = this_loadout_weapons[i];
1203 }
1204 }
1205
1206 // Do a direct restore of the Player_loadout ship/weapon data to the wings
wss_direct_restore_loadout()1207 void wss_direct_restore_loadout()
1208 {
1209 int i, j;
1210 wing *wp;
1211 wss_unit *slot;
1212
1213 // only restore if mission hasn't changed
1214 if ( stricmp(Player_loadout.last_modified, The_mission.modified) != 0 ) {
1215 return;
1216 }
1217
1218 // niffiwan: if Starting_wings[] has missing wings, Player_loadout.unit_data
1219 // skips the missing wings. Use a new variable to track the number of valid
1220 // wings in Starting_wings[], otherwise mission can crash on restart
1221 int valid_wing_index = -1;
1222
1223 for ( i = 0; i < MAX_WING_BLOCKS; i++ ) {
1224
1225 if ( Starting_wings[i] < 0 )
1226 continue;
1227
1228 valid_wing_index++;
1229 wp = &Wings[Starting_wings[i]];
1230
1231 // If this wing is still on the arrival list, then update the parse objects
1232 if ( wp->ship_index[0] == -1 ) {
1233 p_object *p_objp;
1234 j=0;
1235 for ( p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
1236 if ( p_objp->wingnum == WING_INDEX(wp) ) {
1237 // niffiwan: don't overrun the array
1238 if (j >= MAX_WING_SLOTS) {
1239 Warning(LOCATION, "Starting Wing '%s' has more than 'MAX_WING_SLOTS' ships\n", Starting_wing_names[i]);
1240 break;
1241 }
1242 slot = &Player_loadout.unit_data[valid_wing_index*MAX_WING_SLOTS+j];
1243 p_objp->ship_class = slot->ship_class;
1244 wl_update_parse_object_weapons(p_objp, slot);
1245 j++;
1246 }
1247 }
1248 } else {
1249 int k;
1250 int cleanup_ship_index[MAX_WING_SLOTS];
1251 ship *shipp;
1252
1253 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
1254 cleanup_ship_index[k] = -1;
1255 }
1256
1257 // This wing is already created, so directly update the ships
1258 for ( j = 0; j < MAX_WING_SLOTS; j++ ) {
1259 if ( wp->ship_index[j] == -1 ) { // if this is an invalid ship, move on
1260 continue;
1261 }
1262
1263 slot = &Player_loadout.unit_data[valid_wing_index*MAX_WING_SLOTS+j];
1264 shipp = &Ships[wp->ship_index[j]];
1265 if ( shipp->ship_info_index != slot->ship_class ) {
1266
1267 if ( slot->ship_class == -1 ) {
1268 cleanup_ship_index[j] = wp->ship_index[j];
1269 ship_add_exited_ship( shipp, Ship::Exit_Flags::Player_deleted );
1270 obj_delete(shipp->objnum);
1271 hud_set_wingman_status_none( shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
1272 continue;
1273 } else {
1274 change_ship_type(wp->ship_index[j], slot->ship_class);
1275 }
1276 }
1277 wl_bash_ship_weapons(&Ships[wp->ship_index[j]].weapons, slot);
1278 }
1279
1280 for ( k = 0; k < MAX_WING_SLOTS; k++ ) {
1281 if ( cleanup_ship_index[k] != -1 ) {
1282 ship_wing_cleanup( cleanup_ship_index[k], wp );
1283 }
1284 }
1285
1286 }
1287 } // end for
1288 }
wss_slots_all_empty()1289 int wss_slots_all_empty()
1290 {
1291 int i;
1292
1293 Assert( Wss_slots != NULL );
1294
1295 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
1296 if ( Wss_slots[i].ship_class >= 0 )
1297 break;
1298 }
1299
1300 if ( i == MAX_WSS_SLOTS )
1301 return 1;
1302 else
1303 return 0;
1304 }
1305
1306 // determine the mode (WSS_...) based on slot/list index values
wss_get_mode(int from_slot,int from_list,int to_slot,int to_list,int wl_ship_slot)1307 int wss_get_mode(int from_slot, int from_list, int to_slot, int to_list, int wl_ship_slot)
1308 {
1309 int mode, to_slot_empty=0;
1310
1311 Assert( Wss_slots != NULL );
1312
1313 if ( wl_ship_slot >= 0 ) {
1314 // weapons loadout
1315 if ( to_slot >= 0 ) {
1316 if ( Wss_slots[wl_ship_slot].wep_count[to_slot] == 0 ) {
1317 to_slot_empty = 1;
1318 }
1319 }
1320 } else {
1321 // ship select
1322 if ( to_slot >= 0 ) {
1323 if ( Wss_slots[to_slot].ship_class == -1 ){
1324 to_slot_empty = 1;
1325 }
1326 }
1327 }
1328
1329 // determine mode
1330 if ( from_slot >= 0 && to_slot >= 0 ) {
1331 mode = WSS_SWAP_SLOT_SLOT;
1332 } else if ( from_slot >= 0 && to_list >= 0 ) {
1333 mode = WSS_DUMP_TO_LIST;
1334 } else if ( (from_list >= 0) && (to_slot >= 0) && (to_slot_empty) ) {
1335 mode = WSS_GRAB_FROM_LIST;
1336 } else if ( (from_list >= 0) && (to_slot >= 0) && (!to_slot_empty) ) {
1337 mode = WSS_SWAP_LIST_SLOT;
1338 } else {
1339 mode = -1; // no changes required
1340 }
1341
1342 return mode;
1343 }
1344
1345 // store all the unit data and pool data
store_wss_data(ubyte * data,__UNUSED const unsigned int max_size,interface_snd_id sound,int player_index)1346 int store_wss_data(ubyte *data, __UNUSED const unsigned int max_size, interface_snd_id sound, int player_index)
1347 {
1348 int j, i, packet_size = 0;
1349 ubyte val;
1350 short player_id;
1351 ushort pool_size;
1352
1353 // this function assumes that the data is going to be used over the network
1354 // so make a non-network version of this function if needed
1355 Assert( Game_mode & GM_MULTIPLAYER );
1356 Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) );
1357
1358 if ( !(Game_mode & GM_MULTIPLAYER) )
1359 return 0;
1360
1361 // write the ship pool
1362 pool_size = 0;
1363 for (i = 0; i < ship_info_size(); i++) {
1364 if (Ss_pool[i] > 0) {
1365 ++pool_size;
1366 }
1367 }
1368
1369 ADD_USHORT(pool_size);
1370
1371 Assertion((((sizeof(short)+sizeof(short)) * pool_size) + packet_size) < max_size, "Size of ship pool exceeds max data size!");
1372
1373 for (i = 0; i < ship_info_size(); i++) {
1374 if (Ss_pool[i] > 0) {
1375 ADD_SHORT(static_cast<short>(i));
1376 ADD_SHORT(static_cast<short>(Ss_pool[i]));
1377 }
1378 }
1379
1380 // write the weapon pool
1381 pool_size = 0;
1382 for (i = 0; i < weapon_info_size(); i++) {
1383 if (Wl_pool[i] > 0) {
1384 ++pool_size;
1385 }
1386 }
1387
1388 ADD_USHORT(pool_size);
1389
1390 Assertion((((sizeof(short)+sizeof(short)) * pool_size) + packet_size) < max_size, "Size of weapon pool exceeds max data size!");
1391
1392 for (i = 0; i < weapon_info_size(); i++) {
1393 if (Wl_pool[i] > 0) {
1394 ADD_SHORT(static_cast<short>(i));
1395 ADD_SHORT(static_cast<short>(Wl_pool[i]));
1396 }
1397 }
1398
1399 // write the unit data
1400 val = MAX_WSS_SLOTS;
1401 ADD_DATA(val);
1402 val = MAX_SHIP_WEAPONS;
1403 ADD_DATA(val);
1404
1405 Assertion((((sizeof(short) + ((sizeof(short)+sizeof(short)) * MAX_SHIP_WEAPONS)) * MAX_WSS_SLOTS) + packet_size) < max_size, "Size of wss data exceeds max data size!");
1406
1407 for (i = 0; i < MAX_WSS_SLOTS; i++) {
1408 ADD_SHORT(static_cast<short>(Wss_slots[i].ship_class));
1409
1410 for (j = 0; j < MAX_SHIP_WEAPONS; j++) {
1411 ADD_SHORT(static_cast<short>(Wss_slots[i].wep[j]));
1412 Assert(Wss_slots[i].wep_count[j] < SHRT_MAX);
1413 ADD_SHORT(static_cast<short>(Wss_slots[i].wep_count[j]));
1414 }
1415 }
1416
1417 // any sound index
1418 ADD_SHORT(static_cast<short>(sound.value()));
1419
1420 // add a netplayer address to identify who should play the sound
1421 player_id = -1;
1422
1423 if(player_index != -1){
1424 player_id = Net_players[player_index].player_id;
1425 }
1426
1427 ADD_SHORT(player_id);
1428
1429 Assert( packet_size < static_cast<int>(max_size) );
1430 return packet_size;
1431 }
1432
restore_wss_data(ubyte * data)1433 int restore_wss_data(ubyte *data)
1434 {
1435 int i, j, offset = 0;
1436 ubyte num_slots, num_weapons;
1437 short b1, b2;
1438 short player_id, sound;
1439 ushort pool_size;
1440
1441 // this function assumes that the data is going to be used over the network
1442 // so make a non-network version of this function if needed
1443 Assert( Game_mode & GM_MULTIPLAYER );
1444 Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) );
1445
1446 if ( !(Game_mode & GM_MULTIPLAYER) )
1447 return 0;
1448
1449 // restore ship pool
1450 memset(Ss_pool, 0, MAX_SHIP_CLASSES*sizeof(int));
1451 GET_USHORT(pool_size);
1452
1453 for (i = 0; i < pool_size; i++) {
1454 GET_SHORT(b1);
1455 GET_SHORT(b2);
1456
1457 if (b1 < MAX_SHIP_CLASSES) {
1458 Ss_pool[b1] = b2;
1459 }
1460 }
1461
1462 // restore weapons pool
1463 memset(Wl_pool, 0, MAX_WEAPON_TYPES*sizeof(int));
1464 GET_USHORT(pool_size);
1465
1466 for (i = 0; i < pool_size; i++) {
1467 GET_SHORT(b1);
1468 GET_SHORT(b2);
1469
1470 if (b1 < MAX_SHIP_CLASSES) {
1471 Wl_pool[b1] = b2;
1472 }
1473 }
1474
1475
1476 // restore unit data
1477 for (i = 0; i < MAX_WSS_SLOTS; i++) {
1478 Wss_slots[i].ship_class = -1;
1479
1480 for (j = 0; j < MAX_SHIP_WEAPONS; j++) {
1481 Wss_slots[i].wep[j] = -1;
1482 Wss_slots[i].wep_count[j] = 0;
1483 }
1484 }
1485
1486 GET_DATA(num_slots);
1487 GET_DATA(num_weapons);
1488
1489 for (i = 0; i < num_slots; i++) {
1490 GET_SHORT(b1);
1491
1492 if (i < MAX_WSS_SLOTS) {
1493 Wss_slots[i].ship_class = b1;
1494 }
1495
1496 for (j = 0; j < num_weapons; j++) {
1497 GET_SHORT(b1);
1498 GET_SHORT(b2);
1499
1500 if ( (i < MAX_WSS_SLOTS) && (j < MAX_SHIP_WEAPONS) ) {
1501 Wss_slots[i].wep[j] = b1;
1502 Wss_slots[i].wep_count[j] = b2;
1503 }
1504 }
1505 }
1506
1507 // read in the sound data
1508 GET_SHORT(sound);
1509
1510 // read in the player address
1511 GET_SHORT(player_id);
1512
1513 // determine if I'm the guy who should be playing the sound
1514 if((Net_player != NULL) && (Net_player->player_id == player_id)){
1515 // play the sound
1516 if (sound >= 0) {
1517 gamesnd_play_iface(static_cast<InterfaceSounds>(sound));
1518 }
1519 }
1520
1521 if(!(Game_mode & GM_MULTIPLAYER)){
1522 ss_synch_interface();
1523 }
1524
1525 return offset;
1526 }
1527
draw_model_icon(int model_id,int flags,float closeup_zoom,int x,int y,int w,int h,ship_info * sip,int resize_mode,const vec3d * closeup_pos)1528 void draw_model_icon(int model_id, int flags, float closeup_zoom, int x, int y, int w, int h, ship_info *sip, int resize_mode, const vec3d *closeup_pos)
1529 {
1530 matrix object_orient = IDENTITY_MATRIX;
1531 angles rot_angles = vmd_zero_angles;
1532 float zoom = closeup_zoom * 2.5f;
1533
1534 if(sip == NULL)
1535 {
1536 //Assume it's a weapon
1537 rot_angles.h = -(PI_2);
1538 }
1539 else if(sip->model_icon_angles.p != 0.0f || sip->model_icon_angles.b != 0.0f || sip->model_icon_angles.h != 0.0f)
1540 {
1541 // If non-zero model_icon_angles exists, always use that
1542 rot_angles = sip->model_icon_angles;
1543 }
1544 else if(sip->is_small_ship())
1545 {
1546 rot_angles.p = -(PI_2);
1547 }
1548 else if((sip->max_speed <= 0.0f) && !(sip->flags[Ship::Info_Flags::Cargo]))
1549 {
1550 //Probably an installation or Knossos
1551 rot_angles.h = PI;
1552 }
1553 else
1554 {
1555 //Probably a capship
1556 rot_angles.h = PI_2;
1557 }
1558 vm_angles_2_matrix(&object_orient, &rot_angles);
1559
1560 gr_set_clip(x, y, w, h, resize_mode);
1561 g3_start_frame(1);
1562 if(sip != NULL)
1563 {
1564 g3_set_view_matrix( &sip->closeup_pos, &vmd_identity_matrix, zoom);
1565
1566 gr_set_proj_matrix(0.5f*Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
1567 }
1568 else
1569 {
1570 polymodel *pm = model_get(model_id);
1571 bsp_info *bs = NULL; //tehe
1572 for(int i = 0; i < pm->n_models; i++)
1573 {
1574 if(!pm->submodel[i].is_thruster)
1575 {
1576 bs = &pm->submodel[i];
1577 break;
1578 }
1579 }
1580
1581 if(bs == NULL)
1582 {
1583 bs = &pm->submodel[0];
1584 }
1585
1586 vec3d weap_closeup = *closeup_pos;
1587 float y_closeup;
1588 float tm_zoom = closeup_zoom;
1589
1590 //Find the center of teh submodel
1591 weap_closeup.xyz.x = -(bs->min.xyz.z + (bs->max.xyz.z - bs->min.xyz.z)/2.0f);
1592 weap_closeup.xyz.y = -(bs->min.xyz.y + (bs->max.xyz.y - bs->min.xyz.y)/2.0f);
1593 //weap_closeup.xyz.z = (weap_closeup.xyz.x/tanf(zoom / 2.0f));
1594 weap_closeup.xyz.z = -(bs->rad/tanf(tm_zoom/2.0f));
1595
1596 y_closeup = -(weap_closeup.xyz.y/tanf(tm_zoom / 2.0f));
1597 if(y_closeup < weap_closeup.xyz.z)
1598 {
1599 weap_closeup.xyz.z = y_closeup;
1600 }
1601 if(bs->min.xyz.x < weap_closeup.xyz.z)
1602 {
1603 weap_closeup.xyz.z = bs->min.xyz.x;
1604 }
1605 g3_set_view_matrix( &weap_closeup, &vmd_identity_matrix, tm_zoom);
1606
1607 gr_set_proj_matrix(0.5f*Proj_fov, gr_screen.clip_aspect, 0.05f, 1000.0f);
1608 }
1609
1610 model_render_params render_info;
1611 render_info.set_detail_level_lock(0);
1612
1613 gr_set_view_matrix(&Eye_position, &Eye_matrix);
1614
1615 if(!(flags & MR_NO_LIGHTING))
1616 {
1617 light_reset();
1618 vec3d light_dir = vmd_zero_vector;
1619 light_dir.xyz.x = -0.5;
1620 light_dir.xyz.y = 2.0f;
1621 light_dir.xyz.z = -2.0f;
1622 light_add_directional(&light_dir, 0.65f, 1.0f, 1.0f, 1.0f);
1623 light_rotate_all();
1624 }
1625
1626 if (sip != NULL && sip->replacement_textures.size() > 0)
1627 {
1628 render_info.set_replacement_textures(model_id, sip->replacement_textures);
1629 }
1630
1631 Glowpoint_override = true;
1632 model_clear_instance(model_id);
1633
1634 render_info.set_flags(flags);
1635 model_render_immediate(&render_info, model_id, &object_orient, &vmd_zero_vector);
1636 Glowpoint_override = false;
1637
1638 gr_end_view_matrix();
1639 gr_end_proj_matrix();
1640
1641 g3_end_frame();
1642 gr_reset_clip();
1643 }
1644
1645 void light_set_all_relevent();
draw_model_rotating(model_render_params * render_info,int model_id,int x1,int y1,int x2,int y2,float * rotation_buffer,vec3d * closeup_pos,float closeup_zoom,float rev_rate,int flags,int resize_mode,int effect)1646 void draw_model_rotating(model_render_params *render_info, int model_id, int x1, int y1, int x2, int y2, float *rotation_buffer, vec3d *closeup_pos, float closeup_zoom, float rev_rate, int flags, int resize_mode, int effect)
1647 {
1648 //WMC - Can't draw a non-model
1649 if (model_id < 0)
1650 return;
1651
1652 float time = (timer_get_milliseconds()-anim_timer_start)/1000.0f;
1653 angles rot_angles, view_angles;
1654 matrix model_orient;
1655
1656 if (effect == 2) { // FS2 Effect; Phase 0 Expand scanline, Phase 1 scan the grid and wireframe, Phase 2 scan up and reveal the ship, Phase 3 tilt the camera, Phase 4 start rotating the ship
1657 // rotate the ship as much as required for this frame
1658 if (time >= 3.6f) // Phase 4
1659 *rotation_buffer += PI2 * flFrametime / rev_rate;
1660 else
1661 *rotation_buffer = PI; // No rotation before Phase 4
1662 while (*rotation_buffer > PI2){
1663 *rotation_buffer -= PI2;
1664 }
1665
1666 view_angles.p = -PI_2;
1667
1668 if (time >= 3.0f) { // Phase 3
1669 if (time >= 3.6f) { // done tilting
1670 view_angles.p = -0.6f;
1671 } else {
1672 view_angles.p = (PI_2-0.6f)*(time-3.0f)*1.66667f - PI_2; // Phase 3 Tilt animation
1673 }
1674 }
1675
1676 view_angles.b = 0.0f;
1677 view_angles.h = 0.0f;
1678 vm_angles_2_matrix(&model_orient, &view_angles);
1679 rot_angles.p = 0.0f;
1680 rot_angles.b = 0.0f;
1681 rot_angles.h = *rotation_buffer;
1682 vm_rotate_matrix_by_angles(&model_orient, &rot_angles);
1683 gr_set_clip(x1, y1, x2, y2, resize_mode);
1684 vec3d wire_normal,ship_normal,plane_point;
1685
1686 // Clip the wireframe below the scanline
1687 wire_normal.xyz.x = 0.0f;
1688 wire_normal.xyz.y = 1.0f;
1689 wire_normal.xyz.z = 0.0f;
1690
1691 // Clip the ship above the scanline
1692 ship_normal.xyz.x = 0.0f;
1693 ship_normal.xyz.y = -1.0f;
1694 ship_normal.xyz.z = 0.0f;
1695 polymodel *pm = model_get(model_id);
1696
1697 //Make the clipping plane
1698 float clip = -pm->rad*0.7f;
1699 if (time < 1.5f && time >= 0.5f) // Phase 1 Move down
1700 clip = pm->rad*(time-1.0f)*1.4f;
1701
1702 if (time >= 1.5f)
1703 clip = pm->rad*(time-2.0f)*(-1.4f); // Phase 2 Move up
1704
1705 vm_vec_scale_sub(&plane_point,&vmd_zero_vector,&wire_normal,clip);
1706
1707 g3_start_frame(1);
1708 if ( (closeup_pos != NULL) && (vm_vec_mag(closeup_pos) > 0.0f) ) {
1709 g3_set_view_matrix(closeup_pos, &vmd_identity_matrix, closeup_zoom);
1710 } else {
1711 vec3d pos = { { { 0.0f, 0.0f, -(pm->rad * 1.5f) } } };
1712 g3_set_view_matrix(&pos, &vmd_identity_matrix, closeup_zoom);
1713 }
1714
1715 gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
1716 gr_set_view_matrix(&Eye_position, &Eye_matrix);
1717
1718 vec3d start, stop;
1719 float size = pm->rad*0.7f;
1720 float start_scale = MIN(time,0.5f)*2.5f;
1721 float offset = size*0.5f*MIN(MAX(time-3.0f,0.0f),0.6f)*1.66667f;
1722
1723 g3_start_instance_angles(&vmd_zero_vector,&view_angles);
1724
1725 if (time < 0.5f) { // Do the expanding scanline in phase 0
1726 gr_set_color(0,255,0);
1727 start.xyz.x = size*start_scale;
1728 start.xyz.y = 0.0f;
1729 start.xyz.z = -clip;
1730 stop.xyz.x = -size*start_scale;
1731 stop.xyz.y = 0.0f;
1732 stop.xyz.z = -clip;
1733 //g3_draw_htl_line(&start,&stop);
1734 g3_render_line_3d(true, &start, &stop);
1735 }
1736 g3_done_instance(true);
1737
1738 gr_zbuffer_set(GR_ZBUFF_NONE); // Turn off Depthbuffer so we don't get gridlines over the ship or a disappearing scanline
1739 Glowpoint_use_depth_buffer = false; // Since we don't have one
1740 if (time >= 0.5f) { // Phase 1 onward draw the grid
1741 int i;
1742 start.xyz.y = -offset;
1743 start.xyz.z = size+offset*0.5f;
1744 stop.xyz.y = -offset;
1745 stop.xyz.z = -size+offset*0.5f;
1746 gr_set_color(0,200,0);
1747 g3_start_instance_angles(&vmd_zero_vector,&view_angles);
1748
1749 if (time < 1.5f) {
1750 stop.xyz.z = -clip;
1751 }
1752
1753 for (i = -3; i < 4; i++) {
1754 start.xyz.x = stop.xyz.x = size*0.333f*i;
1755 //g3_draw_htl_line(&start,&stop);
1756 g3_render_line_3d(false, &start, &stop);
1757 }
1758
1759 start.xyz.x = size;
1760 stop.xyz.x = -size;
1761
1762 for (i = 3; i > -4; i--) {
1763 start.xyz.z = stop.xyz.z = size*0.333f*i+offset*0.5f;
1764 if ((time < 1.5f) && (start.xyz.z <= -clip))
1765 break;
1766 //g3_draw_htl_line(&start,&stop);
1767 g3_render_line_3d(false, &start, &stop);
1768 }
1769
1770 g3_done_instance(true);
1771
1772 // lighting for techroom
1773 light_reset();
1774 vec3d light_dir = vmd_zero_vector;
1775 light_dir.xyz.y = 1.0f;
1776 light_dir.xyz.x = 0.0000001f;
1777 light_add_directional(&light_dir, 0.65f, 1.0f, 1.0f, 1.0f);
1778 light_rotate_all();
1779 // lighting for techroom
1780
1781 // render the ships
1782 model_clear_instance(model_id);
1783 render_info->set_detail_level_lock(0);
1784
1785 gr_zbuffer_set(true);
1786 if(Shadow_quality != ShadowQuality::Disabled)
1787 {
1788 gr_end_view_matrix();
1789 gr_end_proj_matrix();
1790
1791 gr_reset_clip();
1792
1793 model_render_params shadow_render_info;
1794
1795 shadow_render_info.set_detail_level_lock(0);
1796 shadow_render_info.set_flags(flags | MR_NO_TEXTURING | MR_NO_LIGHTING);
1797
1798 if ( flags & MR_IS_MISSILE ) {
1799 shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos->xyz.z + pm->rad, -closeup_pos->xyz.z + pm->rad + 20.0f, -closeup_pos->xyz.z + pm->rad + 200.0f, -closeup_pos->xyz.z + pm->rad + 1000.0f);
1800 } else {
1801 shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos->xyz.z + pm->rad, -closeup_pos->xyz.z + pm->rad + 200.0f, -closeup_pos->xyz.z + pm->rad + 2000.0f, -closeup_pos->xyz.z + pm->rad + 10000.0f);
1802 }
1803
1804 model_render_immediate(&shadow_render_info, model_id, &model_orient, &vmd_zero_vector);
1805 shadows_end_render();
1806
1807 gr_set_clip(x1, y1, x2, y2, resize_mode);
1808
1809 gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
1810 gr_set_view_matrix(&Eye_position, &Eye_matrix);
1811 }
1812 gr_zbuffer_set(false);
1813 gr_set_color(80,49,160);
1814 render_info->set_color(80, 49, 160);
1815
1816 render_info->set_animated_effect(ANIMATED_SHADER_LOADOUTSELECT_FS2, -clip);
1817
1818 if ( (time < 2.5f) && (time >= 0.5f) ) { // Phase 1 and 2 render the wireframe
1819 if (time >= 1.5f) // Just clip the wireframe after Phase 1
1820 render_info->set_clip_plane(plane_point,wire_normal);
1821
1822 render_info->set_flags(flags | MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_TEXTURING | MR_NO_LIGHTING);
1823
1824 model_render_immediate(render_info, model_id, &model_orient, &vmd_zero_vector);
1825 }
1826
1827 if (time >= 1.5f) { // Render the ship in Phase 2 onwards
1828 render_info->set_clip_plane(plane_point,ship_normal);
1829 render_info->set_flags(flags);
1830
1831 model_render_immediate(render_info, model_id, &model_orient, &vmd_zero_vector);
1832 }
1833
1834 if (time < 2.5f) { // Render the scanline in Phase 1 and 2
1835 gr_set_color(0,255,0);
1836 start.xyz.x = size*1.25f;
1837 start.xyz.y = 0.0f;
1838 start.xyz.z = -clip;
1839 stop.xyz.x = -size*1.25f;
1840 stop.xyz.y = 0.0f;
1841 stop.xyz.z = -clip;
1842 g3_start_instance_angles(&vmd_zero_vector,&view_angles);
1843 //g3_draw_htl_line(&start,&stop);
1844 g3_render_line_3d(false, &start, &stop);
1845 g3_done_instance(true);
1846 }
1847 }
1848
1849 gr_zbuffer_set(GR_ZBUFF_FULL); // Turn off depthbuffer again
1850
1851 batching_render_all();
1852 Glowpoint_use_depth_buffer = true; // Back to normal
1853
1854 gr_end_view_matrix();
1855 gr_end_proj_matrix();
1856 g3_end_frame();
1857 gr_reset_clip();
1858
1859 } else {
1860 // rotate the ship as much as required for this frame
1861 *rotation_buffer += PI2 * flFrametime / rev_rate;
1862 while (*rotation_buffer > PI2){
1863 *rotation_buffer -= PI2;
1864 }
1865
1866 view_angles.p = -0.6f;
1867 view_angles.b = 0.0f;
1868 view_angles.h = 0.0f;
1869 vm_angles_2_matrix(&model_orient, &view_angles);
1870
1871 rot_angles.p = 0.0f;
1872 rot_angles.b = 0.0f;
1873 rot_angles.h = *rotation_buffer;
1874 vm_rotate_matrix_by_angles(&model_orient, &rot_angles);
1875
1876 g3_start_frame(1);
1877
1878 polymodel *pm = model_get(model_id);
1879
1880 // render the wodel
1881 if ( (closeup_pos != NULL) && (vm_vec_mag(closeup_pos) > 0.0f) ) {
1882 g3_set_view_matrix(closeup_pos, &vmd_identity_matrix, closeup_zoom);
1883 } else {
1884 vec3d pos = { { { 0.0f, 0.0f, -(pm->rad * 1.5f) } } };
1885 g3_set_view_matrix(&pos, &vmd_identity_matrix, closeup_zoom);
1886 }
1887
1888 // lighting for techroom
1889 light_reset();
1890 vec3d light_dir = vmd_zero_vector;
1891 light_dir.xyz.y = 1.0f;
1892 light_add_directional(&light_dir, 0.65f, 1.0f, 1.0f, 1.0f);
1893 light_rotate_all();
1894 // lighting for techroom
1895
1896 model_clear_instance(model_id);
1897
1898 render_info->set_detail_level_lock(0);
1899
1900 if(Shadow_quality != ShadowQuality::Disabled)
1901 {
1902 if ( flags & MR_IS_MISSILE ) {
1903 shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos->xyz.z + pm->rad, -closeup_pos->xyz.z + pm->rad + 20.0f, -closeup_pos->xyz.z + pm->rad + 200.0f, -closeup_pos->xyz.z + pm->rad + 1000.0f);
1904 } else {
1905 shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos->xyz.z + pm->rad, -closeup_pos->xyz.z + pm->rad + 200.0f, -closeup_pos->xyz.z + pm->rad + 2000.0f, -closeup_pos->xyz.z + pm->rad + 10000.0f);
1906 }
1907
1908 model_render_params shadow_render_info;
1909
1910 shadow_render_info.set_flags(flags | MR_NO_TEXTURING | MR_NO_LIGHTING);
1911 shadow_render_info.set_detail_level_lock(0);
1912
1913 model_render_immediate(&shadow_render_info, model_id, &model_orient, &vmd_zero_vector);
1914 shadows_end_render();
1915 }
1916
1917 gr_set_clip(x1, y1, x2, y2, resize_mode);
1918
1919 gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
1920 gr_set_view_matrix(&Eye_position, &Eye_matrix);
1921
1922 gr_set_color(0,128,0);
1923
1924 if (effect == 1) { // FS1 effect
1925 render_info->set_animated_effect(ANIMATED_SHADER_LOADOUTSELECT_FS1, MIN(time*0.5f,2.0f));
1926 render_info->set_flags(flags);
1927 } else {
1928 render_info->set_flags(flags);
1929 }
1930
1931 model_render_immediate(render_info, model_id, &model_orient, &vmd_zero_vector);
1932
1933 batching_render_all();
1934
1935 gr_end_view_matrix();
1936 gr_end_proj_matrix();
1937 g3_end_frame();
1938 gr_reset_clip();
1939 }
1940 }
1941
1942 // NEWSTUFF END
1943