FS2_Open
Open source remastering of the Freespace 2 engine
freespace.cpp
Go to the documentation of this file.
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 #ifdef _WIN32
14  #include <direct.h>
15  #include <io.h>
16  #include <windows.h>
17 #ifndef _MINGW
18  #include <crtdbg.h>
19 #endif // !_MINGW
20 #else
21  #include <unistd.h>
22  #include <sys/stat.h>
23 #endif
24 
25 #include "anim/animplay.h"
26 #include "asteroid/asteroid.h"
27 #include "autopilot/autopilot.h"
28 #include "bmpman/bmpman.h"
29 #include "cfile/cfile.h"
30 #include "cmdline/cmdline.h"
31 #include "cmeasure/cmeasure.h"
32 #include "cutscene/cutscenes.h"
33 #include "cutscene/movie.h"
34 #include "debris/debris.h"
35 #include "debugconsole/console.h"
37 #include "external_dll/trackirpublic.h" // header file for the TrackIR routines (Swifty)
38 #include "fireball/fireballs.h"
39 #include "freespace2/freespace.h"
41 #include "freespace2/levelpaging.h"
42 #include "fs2netd/fs2netd_client.h"
43 #include "gamehelp/contexthelp.h"
44 #include "gamehelp/gameplayhelp.h"
46 #include "gamesnd/eventmusic.h"
47 #include "gamesnd/gamesnd.h"
48 #include "globalincs/alphacolors.h"
50 #include "globalincs/version.h"
51 #include "graphics/font.h"
52 #include "graphics/shadows.h"
53 #include "hud/hud.h"
54 #include "hud/hudconfig.h"
55 #include "hud/hudescort.h"
56 #include "hud/hudlock.h"
57 #include "hud/hudmessage.h"
58 #include "hud/hudparse.h"
59 #include "hud/hudshield.h"
60 #include "hud/hudsquadmsg.h"
61 #include "hud/hudtargetbox.h"
62 #include "iff_defs/iff_defs.h"
63 #include "io/joy.h"
64 #include "io/joy_ff.h"
65 #include "io/key.h"
66 #include "io/mouse.h"
67 #include "io/timer.h"
68 #include "jumpnode/jumpnode.h"
69 #include "lab/lab.h"
70 #include "lab/wmcgui.h" //So that GUI_System can be initialized
71 #include "lighting/lighting.h"
72 #include "localization/localize.h"
73 #include "math/staticrand.h"
74 #include "menuui/barracks.h"
75 #include "menuui/credits.h"
76 #include "menuui/mainhallmenu.h"
77 #include "menuui/optionsmenu.h"
78 #include "menuui/playermenu.h"
79 #include "menuui/readyroom.h"
80 #include "menuui/snazzyui.h"
81 #include "menuui/techmenu.h"
82 #include "menuui/trainingmenu.h"
85 #include "mission/missiongoals.h"
86 #include "mission/missionhotkey.h"
87 #include "mission/missionload.h"
88 #include "mission/missionlog.h"
89 #include "mission/missionmessage.h"
90 #include "mission/missionparse.h"
93 #include "missionui/missionbrief.h"
97 #include "missionui/missionpause.h"
101 #include "missionui/redalert.h"
102 #include "mod_table/mod_table.h"
103 #include "nebula/neb.h"
104 #include "nebula/neblightning.h"
105 #include "network/multi.h"
106 #include "network/multi_dogfight.h"
107 #include "network/multi_endgame.h"
108 #include "network/multi_ingame.h"
109 #include "network/multi_log.h"
110 #include "network/multi_pause.h"
111 #include "network/multi_pxo.h"
112 #include "network/multi_rate.h"
113 #include "network/multi_respawn.h"
114 #include "network/multi_voice.h"
115 #include "network/multimsgs.h"
116 #include "network/multiteamselect.h"
117 #include "network/multiui.h"
118 #include "network/multiutil.h"
119 #include "network/stand_gui.h"
120 #include "object/objcollide.h"
121 #include "object/objectsnd.h"
122 #include "object/waypoint.h"
123 #include "observer/observer.h"
124 #include "osapi/osapi.h"
125 #include "osapi/osregistry.h"
126 #include "parse/encrypt.h"
127 #include "parse/generic_log.h"
128 #include "parse/lua.h"
129 #include "parse/parselo.h"
130 #include "parse/scripting.h"
131 #include "parse/sexp.h"
132 #include "particle/particle.h"
133 #include "pilotfile/pilotfile.h"
134 #include "playerman/managepilot.h"
135 #include "playerman/player.h"
136 #include "popup/popup.h"
137 #include "popup/popupdead.h"
138 #include "radar/radar.h"
139 #include "radar/radarsetup.h"
140 #include "render/3d.h"
141 #include "ship/afterburner.h"
142 #include "ship/awacs.h"
143 #include "ship/ship.h"
144 #include "ship/shipcontrails.h"
145 #include "ship/shipfx.h"
146 #include "ship/shiphit.h"
147 #include "sound/audiostr.h"
148 #include "sound/ds.h"
149 #include "sound/fsspeech.h"
150 #include "sound/sound.h"
151 #include "sound/voicerec.h"
152 #include "starfield/starfield.h"
153 #include "starfield/supernova.h"
154 #include "stats/medals.h"
155 #include "stats/stats.h"
156 #include "weapon/beam.h"
157 #include "weapon/emp.h"
158 #include "weapon/flak.h"
159 #include "weapon/muzzleflash.h"
160 #include "weapon/shockwave.h"
161 #include "weapon/weapon.h"
162 
163 #include <stdexcept>
164 
165 extern int Om_tracker_flag; // needed for FS2OpenPXO config
166 
167 #ifdef WIN32
168 // According to AMD and NV, these _should_ force their drivers into high-performance mode
169 extern "C" {
170  __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
171  __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
172 }
173 #endif
174 
175 #ifdef NDEBUG
176 #ifdef FRED
177 #error macro FRED is defined when trying to build release FreeSpace. Please undefine FRED macro in build settings
178 #endif
179 #endif
180 
181 
182 // Revision history.
183 // Full version:
184 // 1.00.04 5/26/98 MWA -- going final (12 pm)
185 // 1.00.03 5/26/98 MWA -- going final (3 am)
186 // 1.00.02 5/25/98 MWA -- going final
187 // 1.00.01 5/25/98 MWA -- going final
188 // 0.90 5/21/98 MWA -- getting ready for final.
189 // 0.10 4/9/98. Set by MK.
190 //
191 // OEM version:
192 // 1.00 5/28/98 AL. First release to Interplay QA.
193 
194 
195 // This function is defined in code\network\multiutil.cpp so will be linked from multiutil.obj
196 // it's required fro the -missioncrcs command line option - Kazan
197 void multi_spew_pxo_checksums(int max_files, const char *outfile);
198 void fs2netd_spew_table_checksums(char *outfile);
199 
200 extern bool frame_rate_display;
201 
202 bool Env_cubemap_drawn = false;
203 
204 void game_reset_view_clip();
206 void game_post_level_init();
207 void game_do_frame();
208 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
209 void game_reset_time();
210 void game_show_framerate(); // draws framerate in lower right corner
211 
213 
214 typedef struct big_expl_flash {
215  float max_flash_intensity; // max intensity
216  float cur_flash_intensity; // cur intensity
217  int flash_start; // start time
219 
220 #define FRAME_FILTER 16
221 
222 #define DEFAULT_SKILL_LEVEL 1
224 
225 #define EXE_FNAME ("fs2.exe")
226 
227 #define LAUNCHER_FNAME ("Launcher.exe")
228 
229 // JAS: Code for warphole camera.
230 // Needs to be cleaned up.
231 float Warpout_time = 0.0f;
232 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
233 int Warpout_sound = -1;
236 #ifndef NDEBUG
238 #endif
240 object *Last_view_target = NULL;
241 
243 
244 int frame_int = -1;
246 float frametotal = 0.0f;
250 
251 #ifndef NDEBUG
252  int Show_framerate = 1;
253  int Show_mem = 1;
254 #else
255  int Show_framerate = 0;
256  int Show_mem = 0;
257 #endif
258 
259 int Framerate_cap = 120;
260 
261 // to determine if networking should be disabled, needs to be done first thing
263 
264 // for the model page in system
265 extern void model_page_in_start();
266 
267 int Show_cpu = 0;
270 int Game_font = -1;
271 #ifndef NDEBUG
272 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
273 #endif
274 
275 int Debug_octant = -1;
276 
280 bool Time_compression_locked = false; //Can the user change time with shift- controls?
281 
282 // auto-lang stuff
283 int detect_lang();
284 
285 // table checksums that will be used for pilot files
288 
289 // if the ships.tbl the player has is valid
291 
292 // if the weapons.tbl the player has is valid
294 
295 int Test_begin = 0;
296 extern int Player_attacking_enabled;
298 
300 
301 int Fred_running = 0;
302 
303 // required for hudtarget... kinda dumb, but meh
306 
310 
311 int game_zbuffer = 1;
312 static int Game_paused;
313 
314 #define EXPIRE_BAD_CHECKSUM 1
315 #define EXPIRE_BAD_TIME 2
316 
317 extern void ssm_init();
318 extern void ssm_level_init();
319 extern void ssm_process();
320 
321 // static variable to contain the time this version was built
322 // commented out for now until
323 // I figure out how to get the username into the file
324 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
325 
326 // defines and variables used for dumping frame for making trailers.
327 #ifndef NDEBUG
328 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
332 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
333 #endif
334 
335 // amount of time to wait after the player has died before we display the death died popup
336 #define PLAYER_DIED_POPUP_WAIT 2500
338 
340 
342 
343 // builtin mission list stuff
346  // single player campaign
347  { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
348 
349  // act 1
350  { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
351  { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
352  { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
353  { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
354  { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
355  { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
356  { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
357  { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
358  { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
359  { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
360  { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
361  { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
362  { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
363  { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
364  { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
365  { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
366  { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
367  { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
368  { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
369 
370  // act 2
371  { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
372  { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
373  { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
374  { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
375  { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
376  { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
377  { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
378  { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
379  { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
380  { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
381 
382  // act 3
383  { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
384  { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
385  { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
386  { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
387  { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
388  { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
389  { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
390  { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
391  { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
392  { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
393  { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
394  { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
395 
396  // multiplayer missions
397 
398  // gauntlet
399  { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
400  { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
401  { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
402 
403  // coop
404  { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
405  { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
406  { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
407  { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
408 
409  // dogfight
410  { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
411  { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
412  { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
413  { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
414  { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
415  { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
416  { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
417  { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
418  { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
419  { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
420  { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
421  { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
422  { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
423  { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
424  { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
425  { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
426  { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
427  { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
428  { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
429  { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
430  { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
431  { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
432  { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
433  { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
434  { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
435  { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
436  { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
437  { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
438 
439  // TvT
440  { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
441  { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
442  { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
443  { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
444  { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
445  { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
446  { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
447  { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
448  { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
449  { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
450 
451  // campaign
452  { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
453  { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
454  { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
455  { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
456  { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
457 };
458 
459 
460 // Internal function prototypes
461 void game_maybe_draw_mouse(float frametime);
463 void load_animating_pointer(char *filename);
466 void game_shutdown(void);
467 void game_show_event_debug(float frametime);
468 void game_event_debug_init();
469 void game_frame(bool paused = false);
472 void verify_ships_tbl();
473 void verify_weapons_tbl();
476 
477 // loading background filenames
478 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
479  "LoadingBG", // GR_640
480  "2_LoadingBG" // GR_1024
481 };
482 
483 
484 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
485  "Loading", // GR_640
486  "2_Loading" // GR_1024
487 };
488 
489 static char *Game_title_screen_fname[GR_NUM_RESOLUTIONS] = {
490  "PreLoad",
491  "2_PreLoad"
492 };
493 
494 static char *Game_logo_screen_fname[GR_NUM_RESOLUTIONS] = {
495  "PreLoadLogo",
496  "2_PreLoadLogo"
497 };
498 
499 // for title screens
500 static int Game_title_bitmap = -1;
501 static int Game_title_logo = -1;
502 
503 // cdrom stuff
505 int init_cdrom();
506 
507 // How much RAM is on this machine. Set in WinMain
509 
510 // game flash stuff
511 float Game_flash_red = 0.0f;
512 float Game_flash_green = 0.0f;
513 float Game_flash_blue = 0.0f;
514 float Sun_spot = 0.0f;
515 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
516 
517 // game shudder stuff (in ms)
520 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
521 
522 // EAX stuff
526 
527 
529 {
530  int idx;
531 
532  // look through all existing builtin missions
533  for(idx=0; idx<Game_builtin_mission_count; idx++){
534  if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
535  return &Game_builtin_mission_list[idx];
536  }
537  }
538 
539  // didn't find it
540  return NULL;
541 }
542 
544 {
545  return DEFAULT_SKILL_LEVEL;
546 }
547 
548 // Resets the flash
550 {
551  Game_flash_red = 0.0f;
552  Game_flash_green = 0.0f;
553  Game_flash_blue = 0.0f;
554  Sun_spot = 0.0f;
555  Big_expl_flash.max_flash_intensity = 0.0f;
556  Big_expl_flash.cur_flash_intensity = 0.0f;
557  Big_expl_flash.flash_start = 0;
558 }
559 
560 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
561 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
562 
564 {
565  // zero critical time
566  Gf_critical_time = 0.0f;
567 
568  // nebula missions
570  Gf_critical = 15.0f;
571  } else {
572  Gf_critical = 25.0f;
573  }
574 }
575 
576 extern float Framerate;
578 {
579  int y_start = gr_screen.center_offset_y + 100;
580 
581  // if the current framerate is above the critical level, add frametime
582  if(Framerate >= Gf_critical){
583  Gf_critical_time += flFrametime;
584  }
585 
586  if (!Show_framerate) {
587  return;
588  }
589 
590  // display if we're above the critical framerate
591  if(Framerate < Gf_critical){
593  gr_string(gr_screen.center_offset_x + 200, y_start, "Framerate warning", GR_RESIZE_NONE);
594 
595  y_start += 10;
596  }
597 
598  // display our current pct of good frametime
599  if(f2fl(Missiontime) >= 0.0f){
600  float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
601 
602  if(pct >= 85.0f){
604  } else {
606  }
607 
608  gr_printf_no_resize(gr_screen.center_offset_x + 200, y_start, "%d%%", (int)pct);
609 
610  y_start += 10;
611  }
612 }
613 
614 
625 void game_flash( float r, float g, float b )
626 {
627  Game_flash_red += r;
628  Game_flash_green += g;
629  Game_flash_blue += b;
630 
631  if ( Game_flash_red < -1.0f ) {
632  Game_flash_red = -1.0f;
633  } else if ( Game_flash_red > 1.0f ) {
634  Game_flash_red = 1.0f;
635  }
636 
637  if ( Game_flash_green < -1.0f ) {
638  Game_flash_green = -1.0f;
639  } else if ( Game_flash_green > 1.0f ) {
640  Game_flash_green = 1.0f;
641  }
642 
643  if ( Game_flash_blue < -1.0f ) {
644  Game_flash_blue = -1.0f;
645  } else if ( Game_flash_blue > 1.0f ) {
646  Game_flash_blue = 1.0f;
647  }
648 
649 }
650 
655 void big_explosion_flash(float flash)
656 {
657  CLAMP(flash, 0.0f, 1.0f);
658 
659  Big_expl_flash.flash_start = timestamp(1);
660  Big_expl_flash.max_flash_intensity = flash;
661  Big_expl_flash.cur_flash_intensity = 0.0f;
662 }
663 
664 // Amount to diminish palette towards normal, per second.
665 #define DIMINISH_RATE 0.75f
666 #define SUN_DIMINISH_RATE 6.00f
667 
668 int Sun_drew = 0;
669 
670 float sn_glare_scale = 1.7f;
671 DCF(sn_glare, "Sets the sun glare scale (Default is 1.7)")
672 {
673  dc_stuff_float(&sn_glare_scale);
674 }
675 
676 float Supernova_last_glare = 0.0f;
677 bool stars_sun_has_glare(int index);
678 extern bool ls_on;
679 extern bool ls_force_off;
680 void game_sunspot_process(float frametime)
681 {
682  int n_lights, idx;
683  int sn_stage;
684  float Sun_spot_goal = 0.0f;
685 
686  // supernova
687  sn_stage = supernova_active();
688  if(sn_stage){
689  // sunspot differently based on supernova stage
690  switch(sn_stage){
691  // approaching. player still in control
692  case 1:
693  float pct;
694  pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
695 
696  vec3d light_dir;
697  light_get_global_dir(&light_dir, 0);
698  float dot;
699  dot = vm_vec_dot( &light_dir, &Eye_matrix.vec.fvec );
700 
701  if(dot >= 0.0f){
702  // scale it some more
703  dot = dot * (0.5f + (pct * 0.5f));
704  dot += 0.05f;
705 
706  Sun_spot_goal += (dot * sn_glare_scale);
707  }
708 
709  // draw the sun glow
711  // draw the glow for this sun
713  }
714 
715  Supernova_last_glare = Sun_spot_goal;
716  break;
717 
718  // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
719  case 2:
720  case 3:
721  Sun_spot_goal = 0.9f;
722  Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
723 
724  if(Sun_spot_goal > 1.0f){
725  Sun_spot_goal = 1.0f;
726  }
727 
728  Sun_spot_goal *= sn_glare_scale;
729  Supernova_last_glare = Sun_spot_goal;
730  break;
731 
732  // fade to white. display dead popup
733  case 4:
734  case 5:
735  Supernova_last_glare += (2.0f * flFrametime);
736  if(Supernova_last_glare > 2.0f){
737  Supernova_last_glare = 2.0f;
738  }
739 
740  Sun_spot_goal = Supernova_last_glare;
741  break;
742  }
743 
744  Sun_drew = 0;
745  } else {
746  Sun_spot_goal = 0.0f;
747  if ( Sun_drew ) {
748  // check sunspots for all suns
749  n_lights = light_get_global_count();
750 
751  // check
752  for(idx=0; idx<n_lights; idx++) {
753  bool in_shadow = shipfx_eye_in_shadow(&Eye_position, Viewer_obj, idx);
754 
755  if ( (ls_on && !ls_force_off) || !in_shadow ) {
756  vec3d light_dir;
757  light_get_global_dir(&light_dir, idx);
758 
759  //only do sunglare stuff if this sun has one
760  if (stars_sun_has_glare(idx)) {
761  float dot = vm_vec_dot( &light_dir, &Eye_matrix.vec.fvec )*0.5f+0.5f;
762  Sun_spot_goal += (float)pow(dot,85.0f);
763  }
764  }
765  if ( !in_shadow ) {
766  // draw the glow for this sun
767  stars_draw_sun_glow(idx);
768  }
769  }
770 
771  Sun_drew = 0;
772  }
773  }
774 
775  float dec_amount = frametime*SUN_DIMINISH_RATE;
776 
777  if ( Sun_spot < Sun_spot_goal ) {
778  Sun_spot += dec_amount;
779  if ( Sun_spot > Sun_spot_goal ) {
780  Sun_spot = Sun_spot_goal;
781  }
782  } else if ( Sun_spot > Sun_spot_goal ) {
783  Sun_spot -= dec_amount;
784  if ( Sun_spot < Sun_spot_goal ) {
785  Sun_spot = Sun_spot_goal;
786  }
787  }
788 }
789 
790 
795 void game_flash_diminish(float frametime)
796 {
797  float dec_amount = frametime*DIMINISH_RATE;
798 
799  if ( Game_flash_red > 0.0f ) {
800  Game_flash_red -= dec_amount;
801  if ( Game_flash_red < 0.0f )
802  Game_flash_red = 0.0f;
803  } else {
804  Game_flash_red += dec_amount;
805  if ( Game_flash_red > 0.0f )
806  Game_flash_red = 0.0f;
807  }
808 
809  if ( Game_flash_green > 0.0f ) {
810  Game_flash_green -= dec_amount;
811  if ( Game_flash_green < 0.0f )
812  Game_flash_green = 0.0f;
813  } else {
814  Game_flash_green += dec_amount;
815  if ( Game_flash_green > 0.0f )
816  Game_flash_green = 0.0f;
817  }
818 
819  if ( Game_flash_blue > 0.0f ) {
820  Game_flash_blue -= dec_amount;
821  if ( Game_flash_blue < 0.0f )
822  Game_flash_blue = 0.0f;
823  } else {
824  Game_flash_blue += dec_amount;
825  if ( Game_flash_blue > 0.0f )
826  Game_flash_blue = 0.0f;
827  }
828 
829  // update big_explosion_cur_flash
830 #define TIME_UP 1500
831 #define TIME_DOWN 2500
832  int duration = TIME_UP + TIME_DOWN;
833  int time = timestamp_until(Big_expl_flash.flash_start);
834  if (time > -duration) {
835  time = -time;
836  if (time < TIME_UP) {
837  Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
838  } else {
839  time -= TIME_UP;
840  Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
841  }
842  }
843 
844  if ( Use_palette_flash ) {
845  int r,g,b;
846 
847  // Change the 200 to change the color range of colors.
848  r = fl2i( Game_flash_red*128.0f );
849  g = fl2i( Game_flash_green*128.0f );
850  b = fl2i( Game_flash_blue*128.0f );
851 
852  if ( Sun_spot > 0.0f && (!ls_on || ls_force_off)) {
853  r += fl2i(Sun_spot*128.0f);
854  g += fl2i(Sun_spot*128.0f);
855  b += fl2i(Sun_spot*128.0f);
856  }
857 
858  if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
859  r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
860  g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
861  b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
862  }
863 
864  if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
865  if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
866  if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
867 
868  if ( (r!=0) || (g!=0) || (b!=0) ) {
869  gr_flash( r, g, b );
870  }
871  }
872 
873 }
874 
875 
877 {
878  //WMC - this is actually pretty damn dangerous, but I don't want a modder
879  //to accidentally use an override here without realizing it.
881  {
882  // save player-persistent variables
884 
885  // De-Initialize the game subsystems
886  sexp_music_close(); // Goober5000
889  snd_stop_all();
890  obj_snd_level_close(); // uninit object-linked persistant sounds
891  gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
892  anim_level_close(); // stop and clean up any anim instances
893  message_mission_shutdown(); // called after anim_level_close() to make sure instances are clear
895  fireball_close();
901  flak_level_close(); // unload flak stuff
902  neb2_level_close(); // shutdown gaseous nebula stuff
903  ct_level_close();
906  mission_brief_common_reset(); // close out parsed briefing/mission stuff
907  cam_close();
908  subtitles_close();
909  particle_close();
912  hud_level_close();
915 
916  // be sure to not only reset the time but the lock as well
917  set_time_compression(1.0f, 0.0f);
918  lock_time_compression(false);
919 
921  Game_paused = 0;
922 
923  if (gr_screen.envmap_render_target >= 0) {
926  }
927  }
928 
929  gr_set_ambient_light(120, 120, 120);
930 
932  }
933  else
934  {
935  Error(LOCATION, "Scripting Mission End override is not fully supported yet.");
936  }
937 
939 }
940 
944 
951 {
952  game_busy( NOX("** starting game_level_init() **") );
953  load_gl_init = (uint) time(NULL);
954 
955  // seed the random number generator in multiplayer
956  if ( Game_mode & GM_MULTIPLAYER ) {
957  // seed the generator from the netgame security flags -- ensures that all players in
958  // multiplayer will have the same random number sequence (with static rand functions)
959  srand( Netgame.security );
960 
961  // semirand function needs to get re-initted every time in multiplayer
962  init_semirand();
963  }
964 
965  Framecount = 0;
968 
970  Cheats_enabled = 0;
971 
972  Game_shudder_time = -1;
973 
974  Perspective_locked = false;
975 
976  // reset the geometry map and distortion map batcher, this should to be done pretty soon in this mission load process (though it's not required)
977  batch_reset();
978 
979  // Initialize the game subsystems
980  game_reset_time(); // resets time, and resets saved time too
981 
982  Multi_ping_timestamp = -1;
983 
984  obj_init(); // Must be inited before the other systems
985 
986  if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
987  model_page_in_start(); // mark any existing models as unused but don't unload them yet
988  mprintf(( "Beginning level bitmap paging...\n" ));
990  } else {
991  model_free_all(); // Free all existing models if standalone server
992  }
993 
994  mission_brief_common_init(); // Free all existing briefing/debriefing text
996 
997  NavSystem_Init(); // zero out the nav system
998 
999  ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1000  ship_level_init();
1002  shipfx_flash_init(); // Init the ship gun flash system.
1003  game_flash_reset(); // Reset the flash effect
1004  particle_init(); // Reset the particle system
1005  fireball_init();
1006  debris_init();
1007  shield_hit_init(); // Initialize system for showing shield hits
1008 
1010  mission_log_init();
1011  messages_init();
1012  obj_snd_level_init(); // init object-linked persistant sounds
1013  anim_level_init();
1017  key_level_init();
1021  Missiontime = 0;
1023  Pre_player_entry = 1; // Means the player has not yet entered.
1024  Entry_delay_time = 0; // Could get overwritten in mission read.
1025  observer_init();
1026  flak_level_init(); // initialize flak - bitmaps, etc
1027  ct_level_init(); // initialize ships contrails, etc
1028  awacs_level_init(); // initialize AWACS
1029  beam_level_init(); // initialize beam weapons
1031  ssm_level_init();
1033  cam_init();
1034  snd_aav_init();
1035 
1036  // multiplayer dogfight hack
1037  dogfight_blown = 0;
1038 
1040 
1042  neb2_level_init();
1043  nebl_level_init();
1044 
1045  Last_view_target = NULL;
1046  Game_paused = 0;
1047 
1048  Game_no_clear = 0;
1049 
1050  // campaign wasn't ended
1052 
1053  Env_cubemap_drawn = false;
1054 
1055  load_gl_init = (uint) (time(NULL) - load_gl_init);
1056 
1057  //WMC - Init multi players for level
1058  if (Game_mode & GM_MULTIPLAYER && Player != NULL) {
1060 
1061  // clear multiplayer stats
1063  }
1064 }
1065 
1070 {
1071  game_level_close();
1073 }
1074 
1079 {
1080  Assert( Net_player != NULL );
1081  if (!(Game_mode & GM_MULTIPLAYER)){
1082  return;
1083  }
1084 
1085  // see if this player should be reading/writing data. Bit is set when at join
1086  // screen onward until quits back to main menu.
1088  return;
1089  }
1090 
1092  multi_do_frame();
1093  } else {
1095  }
1096 }
1097 
1098 // An estimate as to how high the count passed to game_loading_callback will go.
1099 // This is just a guess, it seems to always be about the same. The count is
1100 // proportional to the code being executed, not the time, so this works good
1101 // for a bar, assuming the code does about the same thing each time you
1102 // load a level. You can find this value by looking at the return value
1103 // of game_busy_callback(NULL), which I conveniently print out to the
1104 // debug output window with the '=== ENDING LOAD ==' stuff.
1105 #define COUNT_ESTIMATE 425
1106 
1110 
1111 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1112  {
1113  63, 316 // GR_640
1114  },
1115  {
1116  101, 505 // GR_1024
1117  }
1118 };
1119 
1120 #ifndef NDEBUG
1121 extern char Processing_filename[MAX_PATH_LEN];
1122 static int busy_shader_created = 0;
1124 #endif
1125 static int framenum;
1126 
1132 {
1133  int new_framenum;
1135 
1136  Assert( Game_loading_callback_inited==1 );
1137  Assertion( Game_loading_ani.num_frames > 0, "Load Screen animation %s not found, or corrupted. Needs to be an animation with at least 1 frame.", Game_loading_ani.filename );
1138 
1139  int do_flip = 0;
1140 
1141  new_framenum = ((Game_loading_ani.num_frames*count) / COUNT_ESTIMATE)+1;
1142  if ( new_framenum > Game_loading_ani.num_frames-1 ) {
1143  new_framenum = Game_loading_ani.num_frames-1;
1144  } else if ( new_framenum < 0 ) {
1145  new_framenum = 0;
1146  }
1147  //make sure we always run forwards - graphical hack
1148  if(new_framenum > framenum)
1149  framenum = new_framenum;
1150 
1151  if ( Game_loading_ani.num_frames > 0 ) {
1152  GR_MAYBE_CLEAR_RES(Game_loading_background);
1153  if ( Game_loading_background > -1 ) {
1154  gr_set_bitmap( Game_loading_background );
1156  }
1157 
1158  gr_set_bitmap( Game_loading_ani.first_frame + framenum );
1159  gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1], GR_RESIZE_MENU);
1160 
1161  do_flip = 1;
1162  }
1163 
1164 #ifndef NDEBUG
1165  // print the current filename being processed by game_busy(), the shader here is a quick hack
1166  // since the background isn't always drawn so we can't clear the text away from the previous
1167  // filename. the shader is completely opaque to hide the old text. must easier and faster than
1168  // redrawing the entire screen every flip - taylor
1169  if (!busy_shader_created) {
1170  gr_create_shader(&busy_shader, 5, 5, 5, 255);
1171  busy_shader_created = 1;
1172  }
1173 
1174  if (Processing_filename[0] != '\0') {
1175  gr_set_shader(&busy_shader);
1176  gr_shade(0, 0, gr_screen.max_w_unscaled, 17, GR_RESIZE_MENU); // make sure it goes across the entire width
1177 
1179  gr_string(5, 5, Processing_filename, GR_RESIZE_MENU);
1180 
1181  do_flip = 1;
1182  memset( Processing_filename, 0, MAX_PATH_LEN );
1183  }
1184 #endif
1185 
1186 #ifndef NDEBUG
1188  {
1189 #ifdef _WIN32
1190  void memblockinfo_sort();
1191  void memblockinfo_sort_get_entry(int index, char *filename, int *size);
1192 
1193  char mem_buffer[1000];
1194  char filename[35];
1195  int size;
1196  int i;
1197  int line_height = gr_get_font_height() + 1;
1198 
1199  memblockinfo_sort();
1200  for(i = 0; i < 30; i++)
1201  {
1202  memblockinfo_sort_get_entry(i, filename, &size);
1203 
1204  size /= 1024;
1205 
1206  if(size == 0)
1207  break;
1208 
1209  char *short_name = strrchr(filename, '\\');
1210  if(short_name == NULL)
1211  short_name = filename;
1212  else
1213  short_name++;
1214 
1215  sprintf(mem_buffer,"%s:\t%d K", short_name, size);
1216  gr_string( 20, 220 + (i*line_height), mem_buffer, GR_RESIZE_MENU);
1217  }
1218  sprintf(mem_buffer,"Total RAM:\t%d K", TotalRam / 1024);
1219  gr_string( 20, 230 + (i*line_height), mem_buffer, GR_RESIZE_MENU);
1220 #endif // _WIN32
1221  }
1222 #endif // !NDEBUG
1223 
1224  if (do_flip)
1225  gr_flip();
1226 }
1227 
1229 {
1230  Assert( Game_loading_callback_inited==0 );
1231 
1232  Game_loading_background = bm_load(The_mission.loading_screen[gr_screen.res]);
1233 
1234  if (Game_loading_background < 0)
1235  Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1236 
1237  generic_anim_init(&Game_loading_ani, Game_loading_ani_fname[gr_screen.res]);
1238  generic_anim_load(&Game_loading_ani);
1239  Assertion( Game_loading_ani.num_frames > 0, "Load Screen animation %s not found, or corrupted. Needs to be an animation with at least 1 frame.", Game_loading_ani.filename );
1240 
1241  Game_loading_callback_inited = 1;
1242  Mouse_hidden = 1;
1243  framenum = 0;
1245 
1246 
1247 }
1248 
1250 {
1251  Assert( Game_loading_callback_inited==1 );
1252 
1253  // Make sure bar shows all the way over.
1255 
1256  int real_count __UNUSED = game_busy_callback( NULL );
1257  Mouse_hidden = 0;
1258 
1259  Game_loading_callback_inited = 0;
1260 
1261 #ifndef NDEBUG
1262  mprintf(( "=================== ENDING LOAD ================\n" ));
1263  mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1264  mprintf(( "================================================\n" ));
1265 #else
1266  // to remove warnings in release build
1267  real_count = 0;
1268 #endif
1269 
1270  generic_anim_unload(&Game_loading_ani);
1271 
1272  bm_release( Game_loading_background );
1273  common_free_interface_palette(); // restore game palette
1274  Game_loading_background = -1;
1275 
1276  gr_set_font( FONT1 );
1277 }
1278 
1283 {
1284  // do nothing for now
1285 }
1286 
1291 {
1292  if (The_mission.sound_environment.id >= 0) {
1293  Game_sound_env = The_mission.sound_environment;
1294  } else if (SND_ENV_DEFAULT > 0) {
1295  sound_env_get(&Game_sound_env, SND_ENV_DEFAULT);
1296  } else {
1297  Game_sound_env = Game_default_sound_env;
1298  }
1299 
1300  Game_sound_env_update_timestamp = timestamp(1);
1301 }
1302 
1307 {
1308  // called if we're not on a freespace dedicated (non rendering, no pilot) server
1309  // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1310  if(!(Game_mode & GM_STANDALONE_SERVER)){
1311 
1312  mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1313 
1314  game_busy( NOX("** setting up event music **") );
1315  event_music_level_init(-1); // preloads the first 2 seconds for each event music track
1316 
1317  game_busy( NOX("** unloading interface sounds **") );
1318  gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1319 
1320  game_busy( NOX("** preloading common game sounds **") );
1321  gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1322 
1323  if (Cmdline_snd_preload) {
1324  game_busy( NOX("** preloading gameplay sounds **") );
1325  gamesnd_load_gameplay_sounds(); // preload in gameplay sounds if wanted
1326  }
1327 
1328  game_busy( NOX("** assigning sound environment for mission **") );
1329  ship_assign_sound_all(); // assign engine sounds to ships
1330  game_assign_sound_environment(); // assign the sound environment for this mission
1331 
1333 
1334  if (!(Game_mode & GM_MULTIPLAYER)) {
1335  // call function in missionparse.cpp to fixup player/ai stuff.
1336  game_busy( NOX("** fixing up player/ai stuff **") );
1338  }
1339 
1340  // Load in all the bitmaps for this level
1341  level_page_in();
1342 
1343  game_busy( NOX("** finished with level_page_in() **") );
1344 
1345  if(Game_loading_callback_inited) {
1347  }
1348  }
1349  // the only thing we need to call on the standalone for now.
1350  else {
1352 
1353  // Load in all the bitmaps for this level
1354  level_page_in();
1355  }
1356 }
1357 
1364 {
1365  extern void game_environment_map_gen();
1367 
1368  HUD_init();
1370  mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1371 
1373 
1374  // While trying to track down the nebula bug I encountered a cool effect -
1375  // comment this out to fly a mission in a void. Maybe we should develop this
1376  // into a full effect or something, because it is seriously cool.
1378 
1379 #ifndef NDEBUG
1381 #endif
1382 
1385 
1386  // set ambient light for level
1388  (The_mission.ambient_light_level >> 8) & 0xff,
1389  (The_mission.ambient_light_level >> 16) & 0xff);
1390 
1392 
1393  // If this is a red alert mission in campaign mode, bash wingman status
1394  if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1396  }
1397 
1399 
1400  // m!m Make hv.Player available in "On Mission Start" hook
1401  if(Player_obj)
1403 
1404  // HACK: That scripting hook should be in mission so GM_IN_MISSION has to be set
1408 
1409  if (Player_obj)
1410  Script_system.RemHookVar("Player");
1411 }
1412 
1417 {
1418  mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1419 
1420  int s1 __UNUSED = timer_get_milliseconds();
1421 
1422  // clear post processing settings
1424 
1425  get_mission_info(Game_current_mission_filename, &The_mission, false);
1426 
1427  if ( !(Game_mode & GM_STANDALONE_SERVER) )
1429 
1430  game_level_init();
1431 
1432  if (Game_mode & GM_MULTIPLAYER) {
1434 
1435  // clear multiplayer stats
1437  }
1438 
1439  game_busy( NOX("** starting mission_load() **") );
1440  load_mission_load = (uint) time(NULL);
1441  if (mission_load(Game_current_mission_filename)) {
1442  if ( !(Game_mode & GM_MULTIPLAYER) ) {
1443  popup(PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1445  } else {
1447  }
1448 
1449  if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1451  }
1452 
1453  game_level_close();
1454 
1455  return 0;
1456  }
1457  load_mission_load = (uint) (time(NULL) - load_mission_load);
1458 
1459  // free up memory from parsing the mission
1460  extern void stop_parse();
1461  stop_parse();
1462 
1463  game_busy( NOX("** starting game_post_level_init() **") );
1464  load_post_level_init = (uint) time(NULL);
1466  load_post_level_init = (uint) (time(NULL) - load_post_level_init);
1467 
1468 #ifndef NDEBUG
1469  {
1470  void Do_model_timings_test();
1472  }
1473 #endif
1474 
1475  bm_print_bitmaps();
1476 
1477  int e1 __UNUSED = timer_get_milliseconds();
1478 
1479  mprintf(("Level load took %f seconds.\n", (e1 - s1) / 1000.0f ));
1480 
1481  return 1;
1482 }
1483 
1485 #ifndef NDEBUG
1486 
1487 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1488 DCF_BOOL( show_framerate, Show_framerate )
1489 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1490 DCF_BOOL( show_target_weapons, Show_target_weapons )
1491 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1493 DCF_BOOL( zbuffer, game_zbuffer )
1494 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1495 DCF_BOOL( player_attacking, Player_attacking_enabled )
1496 DCF_BOOL( show_waypoints, Show_waypoints )
1497 DCF_BOOL( show_area_effect, Show_area_effect )
1498 DCF_BOOL( show_net_stats, Show_net_stats )
1500 extern int Training_message_method;
1501 DCF_BOOL( training_msg_method, Training_message_method )
1502 DCF_BOOL( show_player_pos, Show_player_pos )
1503 DCF_BOOL(i_framerate, Interface_framerate )
1504 
1505 DCF(warp, "Tests warpin effect")
1506 {
1507  if (dc_optional_string_either("help", "--help")) {
1508  dc_printf( "Params: bool warpin, string Target = ""\n Warps in if true, out if false. Player is target unless specific ship is specified\n" );
1509  return;
1510  } // Else, process command
1511 
1512  // TODO: Provide status flag
1513 
1514  bool warpin;
1515  char target[MAX_NAME_LEN];
1516  int idx = -1;
1517 
1518  dc_stuff_boolean(&warpin);
1520  idx = ship_name_lookup(target);
1521  } // Else, default target to player
1522 
1523  if (idx < 0) {
1524  // Player is target
1525  if (Player_ai->target_objnum > -1) {
1526  if(warpin) {
1528  } else {
1530  }
1531  }
1532  } else {
1533  // Non-player is targer
1534  if (warpin) {
1535  shipfx_warpin_start(&Objects[Ships[idx].objnum]);
1536  } else {
1537  shipfx_warpout_start(&Objects[Ships[idx].objnum]);
1538  }
1539  }
1540 
1541 }
1542 
1543 DCF(show_mem,"Toggles showing mem usage")
1544 {
1545  bool process = true;
1546 
1547  if (dc_optional_string_either("help", "--help")) {
1548  dc_printf( "Usage: (optional) bool Show_mem\n If true, Show_mem is set and Show_cpu is cleared. If false, then Show_mem is cleared. If nothing passed, then toggle.\n" );
1549  process = false;
1550  }
1551 
1552  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1553  dc_printf("Show_mem is %s\n", (Show_mem ? "TRUE" : "FALSE"));
1554  dc_printf("Show_cpu is %s\n", (Show_cpu ? "TRUE" : "FALSE"));
1555  process = false;
1556  }
1557 
1558  if (!process) {
1559  // Help and/or status was given, so don't process the command
1560  return;
1561  } // Else, process the command
1562 
1563  if (!dc_maybe_stuff_boolean(&Show_mem)) {
1564  // Nothing passed, so toggle
1565  Show_mem = !Show_mem;
1566  } // Else, value was set/cleared by user
1567 
1568  // Can't show mem and cpu at same time
1569  if (Show_mem) {
1570  Show_cpu = false;
1571  }
1572 }
1573 
1574 DCF(show_cpu,"Toggles showing cpu usage")
1575 {
1576  bool process = true;
1577 
1578  if (dc_optional_string_either("help", "--help")) {
1579  dc_printf( "Usage: (optional) bool Show_cpu\n If true, Show_cpu is set and Show_mem is cleared. If false, then Show_cpu is cleared. If nothing passed, then toggle.\n" );
1580  process = false;
1581  }
1582 
1583  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1584  dc_printf("Show_cpu is %s\n", (Show_cpu ? "TRUE" : "FALSE"));
1585  dc_printf("Show_mem is %s\n", (Show_mem ? "TRUE" : "FALSE"));
1586  process = false;
1587  }
1588 
1589  if (!process) {
1590  // Help and/or status was given, so don't process the command
1591  return;
1592  } // Else, process the command
1593 
1594  if (!dc_maybe_stuff_boolean(&Show_cpu)) {
1595  // Nothing passed, so toggle
1596  Show_cpu = !Show_cpu;
1597  } // Else, value was set/cleared by user
1598 
1599  // Can't show mem and cpu at same time
1600  if (Show_cpu) {
1601  Show_mem = false;
1602  }
1603 }
1604 
1605 #endif
1606 
1607 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1608 {
1609  bool process = true;
1610 
1611  if (dc_optional_string_either("help", "--help")) {
1612  dc_printf("Usage: use_joy_mouse [bool]\nSets use_joy_mouse to true or false. If nothing passed, then toggles it.\n");
1613  process = false;
1614  }
1615 
1616  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1617  dc_printf("use_joy_mouse is %s\n", (Use_joy_mouse ? "TRUE" : "FALSE"));
1618  process = false;
1619  }
1620 
1621  if (!process) {
1622  return;
1623  }
1624 
1625  if(!dc_maybe_stuff_boolean(&Use_joy_mouse)) {
1626  // Nothing passed, so toggle
1627  Use_joy_mouse = !Use_joy_mouse;
1628  } // Else, value was set/cleared by user
1629 
1630  os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1631 }
1632 
1633 DCF_BOOL(palette_flash, Use_palette_flash);
1634 
1635 int Use_low_mem = 0;
1636 
1637 DCF(low_mem,"Uses low memory settings regardless of RAM")
1638 {
1639  bool process = true;
1640 
1641  if (dc_optional_string_either("help", "--help")) {
1642  dc_printf("Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n");
1643  process = false;
1644  }
1645 
1646  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1647  dc_printf("low_mem is %s\n", (Use_low_mem ? "TRUE" : "FALSE"));
1648  process = false;
1649  }
1650 
1651  if (!process) {
1652  return;
1653  }
1654 
1655  if (!dc_maybe_stuff_boolean(&Use_low_mem)) {
1656  // Nothing passed, so toggle
1657  Use_low_mem = !Use_low_mem;
1658  } // Else, value was set/cleared by user
1659 
1660  os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1661 }
1662 
1663 
1664 #ifndef NDEBUG
1665 
1666 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1667 {
1668  bool process = true;
1669  if (dc_optional_string_either("help", "--help")) {
1670  dc_printf("Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n");
1671  process = false;
1672  }
1673 
1674  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1675  dc_printf("low_mem is %s\n", (Use_fullscreen_at_startup ? "TRUE" : "FALSE"));
1676  process = false;
1677  }
1678 
1679  if (!process) {
1680  return;
1681  }
1682 
1683  if (dc_maybe_stuff_boolean(&Use_fullscreen_at_startup)) {
1684  // Nothing passed, so toggle
1685  Use_fullscreen_at_startup = !Use_fullscreen_at_startup;
1686  } // Else, value was set/cleared by user
1687 
1688  os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1689 }
1690 #endif
1691 
1693 
1694 float FreeSpace_gamma = 1.0f;
1695 
1696 DCF(gamma,"Sets and saves Gamma Factor")
1697 {
1698  if (dc_optional_string_either("help", "--help")) {
1699  dc_printf( "Usage: gamma <float>\n" );
1700  dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
1701  return;
1702  }
1703 
1704  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1705  dc_printf( "Gamma = %.2f\n", FreeSpace_gamma );
1706  return;
1707  }
1708 
1709  if (!dc_maybe_stuff_float(&FreeSpace_gamma)) {
1710  dc_printf( "Gamma reset to 1.0f\n" );
1711  FreeSpace_gamma = 1.0f;
1712  }
1713  if ( FreeSpace_gamma < 0.1f ) {
1714  FreeSpace_gamma = 0.1f;
1715  } else if ( FreeSpace_gamma > 5.0f ) {
1716  FreeSpace_gamma = 5.0f;
1717  }
1718  gr_set_gamma(FreeSpace_gamma);
1719 
1720  char tmp_gamma_string[32];
1721  sprintf( tmp_gamma_string, NOX("%.2f"), FreeSpace_gamma );
1722  os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1723 }
1724 
1725 #ifdef APPLE_APP
1726 char full_path[1024];
1727 #endif
1728 
1733 {
1734  int s1 __UNUSED, e1 __UNUSED;
1735  const char *ptr;
1736  char whee[MAX_PATH_LEN];
1737 
1738  Game_current_mission_filename[0] = 0;
1739 
1740  // Moved from rand32, if we're gonna break, break immediately.
1741  Assert(RAND_MAX == 0x7fff || RAND_MAX >= 0x7ffffffd);
1742  // seed the random number generator
1743  int game_init_seed = (int) time(NULL);
1744  srand( game_init_seed );
1745 
1746  Framerate_delay = 0;
1747 
1748 #ifndef NDEBUG
1749  load_filter_info();
1750 #endif
1751 
1752  // encrypt stuff
1753  encrypt_init();
1754 
1755  // Initialize the timer before the os
1756  timer_init();
1757 
1758 #ifndef NDEBUG
1759  outwnd_init(1);
1760 #endif
1761 
1762  // init os stuff next
1763  if ( !Is_standalone ) {
1765  }
1766  else {
1767  std_init_os();
1768  }
1769 
1770 #ifndef NDEBUG
1771  #if FS_VERSION_REVIS == 0
1772  mprintf(("FreeSpace 2 Open version: %i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD));
1773  #else
1774  mprintf(("FreeSpace 2 Open version: %i.%i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD, FS_VERSION_REVIS));
1775  #endif
1776 
1777  extern void cmdline_debug_print_cmdline();
1779 #endif
1780 
1781  memset(whee, 0, sizeof(whee));
1782 
1784 
1785  strcat_s(whee, DIR_SEPARATOR_STR);
1786  strcat_s(whee, EXE_FNAME);
1787 
1788  profile_init();
1789  //Initialize the libraries
1790  s1 = timer_get_milliseconds();
1791 
1792  if ( cfile_init(whee, strlen(Game_CDROM_dir) ? Game_CDROM_dir : NULL) ) { // initialize before calling any cfopen stuff!!!
1793  exit(1);
1794  }
1795 
1796  e1 = timer_get_milliseconds();
1797 
1798  // initialize localization module. Make sure this is done AFTER initialzing OS.
1799  lcl_init( detect_lang() );
1800  lcl_xstr_init();
1801 
1802  mod_table_init(); // load in all the mod dependent settings
1803 
1804  if (Is_standalone) {
1805  // force off some cmdlines if they are on
1806  Cmdline_spec = 0;
1807  Cmdline_glow = 0;
1808  Cmdline_env = 0;
1809  Cmdline_3dwarp = 0;
1810  Cmdline_normal = 0;
1811 
1812  // now init the standalone server code
1814  }
1815 
1816  // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
1817  verify_ships_tbl();
1818 
1819  // verify that he has a valid weapons.tbl
1821 
1822 
1823  Use_joy_mouse = 0;
1824  Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
1825 
1826 #ifndef NDEBUG
1827  Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
1828 #endif
1829 
1830  // change FPS cap if told to do so (for those who can't use vsync or where vsync isn't enough)
1831  uint max_fps = 0;
1832  if ( (max_fps = os_config_read_uint(NULL, NOX("MaxFPS"), 0)) != 0 ) {
1833  if ( (max_fps > 15) && (max_fps < 120) ) {
1834  Framerate_cap = (int)max_fps;
1835  }
1836  }
1837 
1838  Asteroids_enabled = 1;
1839 
1841 // SOUND INIT START
1843 
1844  if ( !Is_standalone ) {
1845  snd_init();
1846  }
1847 
1848  if(fsspeech_init() == false) {
1849  mprintf(("Failed to init speech\n"));
1850 
1852  {
1853  if(!fsspeech_was_compiled())
1854  MessageBox((HWND)os_get_window(), "Speech is not compiled in this build in code.lib", "FS2_Open Warning", MB_ICONWARNING);
1855  else
1856  MessageBox((HWND)os_get_window(), "Speech is compiled, but failed to init", "FS2_Open Warning", MB_ICONWARNING);
1857  }
1858  } else if(Cmdline_query_speech) {
1859  // Its bad practice to use a negative type, this is an exceptional case
1860  fsspeech_play(-1,"Welcome to FS2 open");
1861  MessageBox((HWND)os_get_window(), "Speech is compiled and initialised and should be working", "FS2_Open Info", MB_OK);
1862  }
1863 
1865 // SOUND INIT END
1867 
1868  if ( gr_init() == false ) {
1869 #ifdef _WIN32
1870  ClipCursor(NULL);
1871  ShowCursor(TRUE);
1872  ShowWindow((HWND)os_get_window(),SW_MINIMIZE);
1873  MessageBox( NULL, "Error intializing graphics!", "Error", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
1874 #elif defined(SCP_UNIX)
1875  fprintf(stderr, "Error initializing graphics!");
1876 
1877  // the default entry should have been created already if it didn't exist, so if we're here then
1878  // the current value is invalid and we need to replace it
1879  os_config_write_string(NULL, NOX("VideocardFs2open"), NOX("OGL -(1024x768)x16 bit"));
1880 
1881  // courtesy
1882  fprintf(stderr, "The default video entry is now in place. Please try running the game again...\n");
1883  fprintf(stderr, "(edit ~/.fs2_open/fs2_open.ini to change from default resolution)\n");
1884 #endif
1885  exit(1);
1886  return;
1887  }
1888 
1889 // Karajorma - Moved here from the sound init code cause otherwise windows complains
1890 #ifdef FS2_VOICER
1892  {
1894 
1895  if(voiceRectOn == false)
1896  {
1897  MessageBox((HWND)os_get_window(), "Failed to init voice rec", "Error", MB_OK);
1898  }
1899  }
1900 
1901 #endif
1902 
1903  // D3D's gamma system now works differently. 1.0 is the default value
1904  ptr = os_config_read_string(NULL, NOX("GammaD3D"), NOX("1.0"));
1905  FreeSpace_gamma = (float)atof(ptr);
1906 
1907  script_init(); //WMC
1908 
1909  gr_font_init(); // loads up all fonts
1910 
1911  // add title screen
1912  if(!Is_standalone){
1913  // #Kazan# - moved this down - WATCH THESE calls - anything that shares code between standalone and normal
1914  // cannot make gr_* calls in standalone mode because all gr_ calls are NULL pointers
1915  gr_set_gamma(FreeSpace_gamma);
1917  }
1918 
1919  // attempt to load up master tracker registry info (login and password)
1920  Multi_tracker_id = -1;
1921 
1922  // should we be using this or not?
1923  Om_tracker_flag = os_config_read_uint( "PXO", "FS2OpenPXO" , 0 );
1924  // pxo login and password
1925  ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
1926  if(ptr == NULL){
1927  nprintf(("Network","Error reading in PXO login data\n"));
1929  } else {
1931  }
1932  ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
1933  if(ptr == NULL){
1934  nprintf(("Network","Error reading PXO password\n"));
1936  } else {
1938  }
1939 
1940  // pxo squad name and password
1941  ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
1942  if(ptr == NULL){
1943  nprintf(("Network","Error reading in PXO squad name\n"));
1945  } else {
1947  }
1948 
1949  // If less than 48MB of RAM, use low memory model.
1950  if (
1951 #ifdef _WIN32
1952  (FreeSpace_total_ram < 48*1024*1024) ||
1953 #endif
1954  Use_low_mem ) {
1955  mprintf(( "Using normal memory settings...\n" ));
1956  bm_set_low_mem(1); // Use every other frame of bitmaps
1957  } else {
1958  mprintf(( "Using high memory settings...\n" ));
1959  bm_set_low_mem(0); // Use all frames of bitmaps
1960  }
1961 
1962  //WMC - Initialize my new GUI system
1963  //This may seem scary, but it should take up 0 processing time and very little memory
1964  //as long as it's not being used.
1965  //Otherwise, it just keeps the parsed interface.tbl in memory.
1966  GUI_system.ParseClassInfo("interface.tbl");
1967 
1968  // load non-darkening pixel defs
1970 
1971  iff_init(); // Goober5000 - this must be done even before species_defs :p
1972  species_init(); // Load up the species defs - this needs to be done FIRST -- Kazan
1973 
1975 
1976  hud_init_comm_orders(); // Goober5000
1977 
1978  control_config_common_init(); // sets up localization stuff in the control config
1979 
1980  parse_rank_tbl();
1981  parse_medal_tbl();
1982 
1983  cutscene_init();
1984  key_init();
1985  mouse_init();
1987 
1988  gameseq_init();
1989 
1990  multi_init();
1991 
1992  // start up the mission logfile
1994  log_string(LOGFILE_EVENT_LOG,"FS2_Open Mission Log - Opened \n\n", 1);
1995 
1996  // standalone's don't use the joystick and it seems to sometimes cause them to not get shutdown properly
1997  if(!Is_standalone){
1998  joy_init();
1999  }
2000 
2002  model_init();
2003 
2004  event_music_init();
2005 
2006  // initialize alpha colors
2007  // CommanderDJ: try with colors.tbl first, then use the old way if that doesn't work
2009 
2010  obj_init();
2011  mflash_game_init();
2012  armor_init();
2013  ai_init();
2014  ai_profiles_init(); // Goober5000
2015  weapon_init();
2016  glowpoint_init();
2017  ship_init(); // read in ships.tbl
2018 
2019  player_init();
2020  mission_campaign_init(); // load in the default campaign
2021  anim_init();
2022  context_help_init();
2023  techroom_intel_init(); // parse species.tbl, load intel info
2024  hud_positions_init(); //Setup hud positions
2025 
2026  // initialize psnet
2027  psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2028 
2030  asteroid_init();
2031  mission_brief_common_init(); // Mark all the briefing structures as empty.
2032 
2033  neb2_init(); // fullneb stuff
2034  nebl_init();
2035  stars_init();
2036  ssm_init();
2037  player_tips_init(); // helpful tips
2038  beam_init();
2039 
2040  // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2043 
2044  load_animating_pointer(NOX("cursor"));
2045 
2047  {
2049  }
2050 
2051  if (Cmdline_env) {
2052  ENVMAP = Default_env_map = bm_load("cubemap");
2053  }
2054 
2055  Viewer_mode = 0;
2056  Game_paused = 0;
2057 
2060 
2062 
2063  // convert old pilot files (if they need it)
2065 
2066 #ifdef _WIN32
2067  timeBeginPeriod(1);
2068 #endif
2069 
2070  nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2071  nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2072 
2073  mprintf(("cfile_init() took %d\n", e1 - s1));
2075 }
2076 
2077 char transfer_text[128];
2078 
2079 float Start_time = 0.0f;
2080 
2081 float Framerate = 0.0f;
2082 
2083 #ifndef NDEBUG
2084 float Timing_total = 0.0f;
2085 float Timing_render2 = 0.0f;
2086 float Timing_render3 = 0.0f;
2087 float Timing_flip = 0.0f;
2088 float Timing_clear = 0.0f;
2089 #endif
2090 
2091 MONITOR(NumPolysDrawn)
2092 MONITOR(NumPolys)
2093 MONITOR(NumVerts)
2094 MONITOR(BmpUsed)
2095 MONITOR(BmpNew)
2096 
2097 
2101 
2103 {
2104  if (frame_int == -1) {
2105  for (int i = 0; i < FRAME_FILTER; i++)
2106  frametimes[i] = 0.0f;
2107 
2108  frametotal = 0.0f;
2109  frame_int = 0;
2110  }
2111 
2112  frametotal -= frametimes[frame_int];
2113  frametotal += flRealframetime;
2114  frametimes[frame_int] = flRealframetime;
2115  frame_int = (frame_int + 1 ) % FRAME_FILTER;
2116 
2117  if (frametotal != 0.0f) {
2118  if (Framecount >= FRAME_FILTER)
2119  Framerate = FRAME_FILTER / frametotal;
2120  else
2121  Framerate = Framecount / frametotal;
2122  }
2123 
2124  Framecount++;
2125 }
2126 
2131 {
2132  float cur_time;
2133  int line_height = gr_get_font_height() + 1;
2134 
2135  cur_time = f2fl(timer_get_approx_seconds());
2136  if (cur_time - Start_time > 30.0f) {
2137  mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2138  Start_time += 1000.0f;
2139  }
2140 
2141 #ifdef WMC
2142  //WMC - this code spits out the target of all turrets
2143  if ( (Player_ai->target_objnum != -1) && (Objects[Player_ai->target_objnum].type == OBJ_SHIP) ) {
2144  //Debug crap
2145  int t = 0;
2146  ship_subsys *pss;
2147 
2149 
2150  object *objp = &Objects[Player_ai->target_objnum];
2151  for ( pss = GET_FIRST(&shipp->subsys_list); pss !=END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
2152  if (pss->system_info->type == SUBSYSTEM_TURRET) {
2153  if(pss->turret_enemy_objnum == -1)
2154  gr_printf_no_resize(gr_screen.center_offset_x + 10, gr_screen.center_offset_y + (t*line_height), "Turret %d: <None>", t);
2155  else if (Objects[pss->turret_enemy_objnum].type == OBJ_SHIP)
2157  else
2158  gr_printf_no_resize(gr_screen.center_offset_x + 10, gr_screen.center_offset_y + (t*line_height), "Turret %d: <Object %d>", t, pss->turret_enemy_objnum);
2159 
2160  t++;
2161  }
2162  }
2163  }
2164 #endif
2165 
2166 
2167  if (Show_framerate || Cmdline_frame_profile) {
2169 
2170  if (Cmdline_frame_profile) {
2172  }
2173 
2174  if (Show_framerate) {
2175  if (frametotal != 0.0f)
2176  gr_printf_no_resize( gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100, "FPS: %0.1f", Framerate );
2177  else
2179  }
2180  }
2181 
2182 #ifndef NDEBUG
2183  if ( Debug_dump_frames )
2184  return;
2185 #endif
2186 
2187  // possibly show control checking info
2189 
2190 #ifdef _WIN32
2191  if (Cmdline_show_stats && HUD_draw) {
2192  int sx,sy;
2193  sx = gr_screen.center_offset_x + 20;
2194  sy = gr_screen.center_offset_y + 100 + (line_height * 2);
2195 
2196  char mem_buffer[50];
2197 
2198  MEMORYSTATUS mem_stats;
2199  GlobalMemoryStatus(&mem_stats);
2200 
2201  // on win2k+, it should be == -1 if >4gig (indicates wrap around)
2202  if ( ((int)Mem_starttime_phys == -1) || ((int)mem_stats.dwAvailPhys == -1) )
2203  sprintf(mem_buffer, "Using Physical: *** (>4G)");
2204  else
2205  sprintf(mem_buffer,"Using Physical: %d Meg",(Mem_starttime_phys - mem_stats.dwAvailPhys)/1024/1024);
2206 
2207  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2208  sy += line_height;
2209  sprintf(mem_buffer,"Using Pagefile: %d Meg",(Mem_starttime_pagefile - mem_stats.dwAvailPageFile)/1024/1024);
2210  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2211  sy += line_height;
2212  sprintf(mem_buffer,"Using Virtual: %d Meg",(Mem_starttime_virtual - mem_stats.dwAvailVirtual)/1024/1024);
2213  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2214  sy += line_height * 2;
2215 
2216  if ( ((int)mem_stats.dwAvailPhys == -1) || ((int)mem_stats.dwTotalPhys == -1) )
2217  sprintf(mem_buffer, "Physical Free: *** / *** (>4G)");
2218  else
2219  sprintf(mem_buffer,"Physical Free: %d / %d Meg",mem_stats.dwAvailPhys/1024/1024, mem_stats.dwTotalPhys/1024/1024);
2220 
2221  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2222  sy += line_height;
2223  sprintf(mem_buffer,"Pagefile Free: %d / %d Meg",mem_stats.dwAvailPageFile/1024/1024, mem_stats.dwTotalPageFile/1024/1024);
2224  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2225  sy += line_height;
2226  sprintf(mem_buffer,"Virtual Free: %d / %d Meg",mem_stats.dwAvailVirtual/1024/1024, mem_stats.dwTotalVirtual/1024/1024);
2227  gr_string( sx, sy, mem_buffer, GR_RESIZE_NONE);
2228  }
2229 #endif
2230 
2231 #ifndef NDEBUG
2232  if ( Show_cpu == 1 ) {
2233 
2234  int sx,sy;
2236  sy = gr_screen.center_offset_y + 15;
2237 
2239 
2240  gr_printf_no_resize( sx, sy, NOX("DMA: %s"), transfer_text );
2241  sy += line_height;
2242  gr_printf_no_resize( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2243  sy += line_height;
2244  gr_printf_no_resize( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2245  sy += line_height;
2246  gr_printf_no_resize( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2247  sy += line_height;
2248 
2249  {
2250 
2251  extern int Num_pairs; // Number of object pairs that were checked.
2252  gr_printf_no_resize( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2253  sy += line_height;
2254 
2255  extern int Num_pairs_checked; // What percent of object pairs were checked.
2256  gr_printf_no_resize( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2257  sy += line_height;
2258  Num_pairs_checked = 0;
2259 
2260  }
2261 
2262  gr_printf_no_resize( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2263  sy += line_height;
2264 
2265  if ( Timing_total > 0.01f ) {
2266  gr_printf_no_resize( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2267  sy += line_height;
2268  gr_printf_no_resize( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2269  sy += line_height;
2270  gr_printf_no_resize( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2271  sy += line_height;
2272  gr_printf_no_resize( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2273  sy += line_height;
2274  gr_printf_no_resize( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2275  sy += line_height;
2276  }
2277  }
2278 
2279  if ( Show_mem ) {
2280 
2281  int sx,sy;
2283  sy = gr_screen.center_offset_y + 15;
2284 
2286 
2287  {
2288  extern int TotalRam;
2289  gr_printf_no_resize( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2290  sy += line_height;
2291  }
2292 
2293  {
2294  extern int Model_ram;
2295  gr_printf_no_resize( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2296  sy += line_height;
2297  }
2298 
2299  gr_printf_no_resize( sx, sy, NOX("%s: %d KB\n"), (Cmdline_cache_bitmaps) ? NOX("C-BMP") : NOX("BMP"), bm_texture_ram/1024 );
2300  sy += line_height;
2301 
2302  gr_printf_no_resize( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2303  sy += line_height;
2304 
2305  {
2306  extern int GL_textures_in;
2307  extern int GL_vertex_data_in;
2308  gr_printf_no_resize( sx, sy, NOX("VRAM: %d KB\n"), (GL_textures_in + GL_vertex_data_in)/1024 );
2309  sy += line_height;
2310  }
2311  }
2312 
2313 
2314  if ( Show_player_pos ) {
2315  int sx, sy;
2316  sx = gr_screen.center_offset_x + 320;
2317  sy = gr_screen.center_offset_y + 100;
2318  gr_printf_no_resize(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.xyz.x), fl2i(Player_obj->pos.xyz.y), fl2i(Player_obj->pos.xyz.z));
2319  }
2320 
2321 #ifdef _WIN32
2322  if (Cmdline_show_mem_usage) {
2323  void memblockinfo_sort();
2324  void memblockinfo_sort_get_entry(int index, char *filename, int *size);
2325 
2326  char mem_buffer[1000];
2327  char filename[MAX_PATH];
2328  int size;
2329 
2330  memblockinfo_sort();
2331 
2332  int mi = 0;
2333  for( ; mi < 30; mi++) {
2334  memblockinfo_sort_get_entry(mi, filename, &size);
2335 
2336  size /= 1024;
2337 
2338  if (size == 0)
2339  break;
2340 
2341  char *short_name = strrchr(filename, '\\');
2342 
2343  if (short_name == NULL)
2344  short_name = filename;
2345  else
2346  short_name++;
2347 
2348  sprintf(mem_buffer,"%s:\t%d K", short_name, size);
2349  gr_string( gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100 + (line_height * 12) + (mi*line_height), mem_buffer, GR_RESIZE_NONE);
2350  }
2351 
2352  sprintf(mem_buffer,"Total RAM:\t%d K", TotalRam / 1024);
2353  gr_string( gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100 + (line_height * 13) + (mi*line_height), mem_buffer, GR_RESIZE_NONE);
2354  }
2355 #endif
2356 
2357  MONITOR_INC(NumPolys, modelstats_num_polys);
2358  MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2359  MONITOR_INC(NumVerts, modelstats_num_verts );
2360 
2365 #endif
2366 }
2367 
2369 {
2370  if ( !Cmdline_show_pos )
2371  return;
2372 
2373  if(!cid.isValid())
2374  return;
2375 
2376  camera *cam = cid.getCamera();
2377  vec3d cam_pos = vmd_zero_vector;
2378  matrix cam_orient = vmd_identity_matrix;
2379  cam->get_info(&cam_pos, &cam_orient);
2380 
2381  //Do stuff
2382  int font_height = 2*gr_get_font_height();
2383  angles rot_angles;
2384 
2386 
2387  //Position
2388  gr_printf_no_resize(gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100 - font_height, "X:%f Y:%f Z:%f", cam_pos.xyz.x, cam_pos.xyz.y, cam_pos.xyz.z);
2389  font_height -= font_height/2;
2390 
2391  //Orientation
2392  vm_extract_angles_matrix(&rot_angles, &cam_orient);
2393  rot_angles.p *= (180/PI);
2394  rot_angles.b *= (180/PI);
2395  rot_angles.h *= (180/PI);
2396  gr_printf_no_resize(gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100 - font_height, "Xr:%f Yr:%f Zr:%f", rot_angles.p, rot_angles.b, rot_angles.h);
2397 }
2398 
2400 {
2401  float frame_rate=30.0f;
2402  if ( frame_int == -1 ) {
2403  int i;
2404  for (i=0; i<FRAME_FILTER; i++ ) {
2405  frametimes[i] = 0.0f;
2406  }
2407  frametotal = 0.0f;
2408  frame_int = 0;
2409  }
2410  frametotal -= frametimes[frame_int];
2411  frametotal += flRealframetime;
2412  frametimes[frame_int] = flRealframetime;
2413  frame_int = (frame_int + 1 ) % FRAME_FILTER;
2414 
2415  if ( frametotal != 0.0 ) {
2416  if ( Framecount >= FRAME_FILTER ){
2417  frame_rate = FRAME_FILTER / frametotal;
2418  } else {
2419  frame_rate = Framecount / frametotal;
2420  }
2421  }
2422  std_set_standalone_fps(frame_rate);
2423  Framecount++;
2424 }
2425 
2434 {
2435  int diff;
2436 
2437  if (Mission_end_time == -1)
2438  return;
2439 
2440  diff = f2i(Mission_end_time - Missiontime);
2441  // be sure to bash to 0. diff could be negative on frame that we quit mission
2442  if (diff < 0)
2443  diff = 0;
2444 
2446  gr_printf_no_resize( gr_screen.center_offset_x + 5, gr_screen.center_offset_y + 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2447 }
2448 
2449 //========================================================================================
2450 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2451 //========================================================================================
2452 
2453 #ifndef NDEBUG
2454 
2455 DCF(ai_pause,"Pauses ai")
2456 {
2457  bool process = true;
2458 
2459  if (dc_optional_string_either("help", "--help")) {
2460  dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2461  process = false;
2462  }
2463 
2464  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2465  dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2466  process = false;
2467  }
2468 
2469  if (!process) {
2470  return;
2471  }
2472 
2474  ai_paused = !ai_paused;
2475  }
2476 
2477  if (ai_paused) {
2479  }
2480 }
2481 
2482 DCF(single_step,"Enables single step mode.")
2483 {
2484  bool process = true;
2485 
2486  if (dc_optional_string_either("help", "--help")) {
2487  dc_printf( "Usage: game_single_step [bool]\nEnables or disables single-step mode. If nothing passed, then toggles it.\nSingle-step mode will freeze the game, and will advance frame by frame with each key press\n");
2488  process = false;
2489  }
2490 
2491  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2492  dc_printf( "ai_paused is %s\n", (game_single_step ? "TRUE" : "FALSE") );
2493  process = false;
2494  }
2495 
2496  if (!process) {
2497  return;
2498  }
2499 
2500  if (!dc_maybe_stuff_boolean(&game_single_step)) {
2501  game_single_step = !game_single_step;
2502  }
2503 
2504  last_single_step = 0; // Make so single step waits a frame before stepping
2505 }
2506 
2507 DCF_BOOL(physics_pause, physics_paused)
2508 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2509 DCF_BOOL(ai_firing, Ai_firing_enabled )
2510 
2511 // Create some simple aliases to these commands...
2512 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2513 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2514 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2515 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2516 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2517 #endif
2518 
2519 //========================================================================================
2520 //========================================================================================
2521 
2522 
2524 {
2525  int key;
2526 
2527  key = game_check_key();
2528  if (key > 0){
2530  }
2531 
2532  gr_flip();
2533 }
2534 
2535 
2537 {
2538  Game_skill_level++;
2539  if (Game_skill_level >= NUM_SKILL_LEVELS){
2540  Game_skill_level = 0;
2541  }
2542 }
2543 
2545 
2546 int View_percent = 100;
2547 
2548 
2549 DCF(view, "Sets the percent of the 3d view to render.")
2550 {
2551  bool process = true;
2552  int value;
2553 
2554  if (dc_optional_string_either("help", "--help")) {
2555  dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2556  process = false;
2557  }
2558 
2559  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2560  dc_printf("View is set to %d%%\n", View_percent );
2561  process = false;
2562  }
2563 
2564  if (!process) {
2565  return;
2566  }
2567 
2568  dc_stuff_int(&value);
2569  if ( (value >= 5 ) && (value <= 100) ) {
2570  View_percent = value;
2571  } else {
2572  dc_printf("Error: Outside legal range [5 - 100]");
2573  }
2574 }
2575 
2576 
2581 {
2583  Cutscene_delta_time = 1.0f;
2584  Cutscene_bars_progress = 1.0f;
2585 }
2586 
2587 void game_set_view_clip(float frametime)
2588 {
2589  if ((Game_mode & GM_DEAD) || (supernova_active() >= 2))
2590  {
2591  // Set the clip region for the letterbox "dead view"
2592  int yborder = gr_screen.max_h/4;
2593 
2594  if (g3_in_frame() == 0) {
2595  // Ensure that the bars are black
2596  gr_set_color(0,0,0);
2597  gr_set_bitmap(0); // Valathil - Don't ask me why this has to be here but otherwise the black bars don't draw
2598  gr_rect(0, 0, gr_screen.max_w, yborder, GR_RESIZE_NONE);
2599  gr_rect(0, gr_screen.max_h-yborder, gr_screen.max_w, yborder, GR_RESIZE_NONE);
2600  } else {
2601  // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2602  // J.S. I've changed my ways!! See the new "no constants" code!!!
2603  gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2, GR_RESIZE_NONE );
2604  }
2605  }
2606  else {
2607  // Set the clip region for normal view
2608  if ( View_percent >= 100 ) {
2609  gr_reset_clip();
2610  } else {
2611  int xborder, yborder;
2612 
2613  if ( View_percent < 5 ) {
2614  View_percent = 5;
2615  }
2616 
2617  float fp = i2fl(View_percent)/100.0f;
2618  int fi = fl2i(fl_sqrt(fp)*100.0f);
2619  if ( fi > 100 ) fi=100;
2620 
2621  xborder = ( gr_screen.max_w*(100-fi) )/200;
2622  yborder = ( gr_screen.max_h*(100-fi) )/200;
2623 
2624  gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2, GR_RESIZE_NONE );
2625  }
2626  }
2627 }
2628 
2629 
2631 {
2632  int i;
2633  int laser_count = 0, missile_count = 0;
2634 
2635  for (i=0; i<MAX_OBJECTS; i++) {
2636  if (Objects[i].type == OBJ_WEAPON){
2637  if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2638  laser_count++;
2639  } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2640  missile_count++;
2641  }
2642  }
2643  }
2644 
2645  nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2646 }
2647 
2648 extern int Tool_enabled;
2649 int tst = 0;
2650 int tst_time = 0;
2651 int tst_big = 0;
2653 int tst_bitmap = -1;
2654 float tst_x, tst_y;
2659 {
2660  // start tst
2661  if(tst == 3){
2662  tst = 0;
2663 
2664  // screen position
2665  vertex v;
2666  g3_rotate_vertex(&v, &tst_pos);
2667  g3_project_vertex(&v);
2668 
2669  // offscreen
2670  if(!(
2671  (v.screen.xyw.x >= 0)
2672  && (v.screen.xyw.x <= gr_screen.max_w)
2673  && (v.screen.xyw.y >= 0)
2674  && (v.screen.xyw.y <= gr_screen.max_h)
2675  ))
2676  {
2677  return;
2678  }
2679 
2680  // big ship? always tst
2681  if(tst_big){
2682  // within 3000 meters
2683  if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2684  tst = 2;
2685  }
2686  } else {
2687  // within 300 meters
2688  if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2689  tst = 2;
2690  }
2691  }
2692  }
2693 
2694 }
2696 {
2697  int left = 0;
2698 
2699  if(!Tool_enabled){
2700  return;
2701  }
2702 
2703  // setup tst
2704  if(tst == 2){
2705  tst_time = (int) time(NULL);
2706 
2707  // load the tst bitmap
2708  switch((int)frand_range(0.0f, 3.0)){
2709  case 0:
2710  tst_bitmap = bm_load("ig_jim");
2711  left = 1;
2712  mprintf(("TST 0\n"));
2713  break;
2714 
2715  case 1:
2716  tst_bitmap = bm_load("ig_kan");
2717  left = 0;
2718  mprintf(("TST 1\n"));
2719  break;
2720 
2721  case 2:
2722  tst_bitmap = bm_load("ig_jim");
2723  left = 1;
2724  mprintf(("TST 2\n"));
2725  break;
2726 
2727  default:
2728  tst_bitmap = bm_load("ig_kan");
2729  left = 0;
2730  mprintf(("TST 3\n"));
2731  break;
2732  }
2733 
2734  if(tst_bitmap < 0){
2735  tst = 0;
2736  return;
2737  }
2738 
2739  // get the tst bitmap dimensions
2740  int w, h;
2741  bm_get_info(tst_bitmap, &w, &h);
2742 
2743  // tst y
2744  tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2745 
2747 
2748  // tst x and direction
2749  tst_mode = 0;
2750  if(left){
2751  tst_x = (float)-w;
2752  tst_offset_total = (float)w;
2753  tst_offset = (float)w;
2754  } else {
2755  tst_x = (float)gr_screen.max_w;
2756  tst_offset_total = (float)-w;
2757  tst_offset = (float)w;
2758  }
2759 
2760  tst = 1;
2761  }
2762 
2763  // run tst
2764  if(tst == 1){
2765  float diff = (tst_offset_total / 0.5f) * flFrametime;
2766 
2767  // move the bitmap
2768  if(tst_mode == 0){
2769  tst_x += diff;
2770 
2771  tst_offset -= fl_abs(diff);
2772  } else if(tst_mode == 2){
2773  tst_x -= diff;
2774 
2775  tst_offset -= fl_abs(diff);
2776  }
2777 
2778  // draw the bitmap
2779  gr_set_bitmap(tst_bitmap);
2780  gr_bitmap((int)tst_x, (int)tst_y, GR_RESIZE_NONE);
2781 
2782  if(tst_mode == 1){
2783  if(timestamp_elapsed_safe(tst_stamp, 1100)){
2784  tst_mode = 2;
2785  }
2786  } else {
2787  // if we passed the switch point
2788  if(tst_offset <= 0.0f){
2789  // switch modes
2790  switch(tst_mode){
2791  case 0:
2792  tst_mode = 1;
2793  tst_stamp = timestamp(1000);
2794  tst_offset = fl_abs(tst_offset_total);
2795  break;
2796 
2797  case 2:
2798  tst = 0;
2799  return;
2800  }
2801  }
2802  }
2803  }
2804 }
2805 void game_tst_mark(object *objp, ship *shipp)
2806 {
2807  ship_info *sip;
2808 
2809  if(!Tool_enabled){
2810  return;
2811  }
2812 
2813  // bogus
2814  if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= static_cast<int>(Ship_info.size()))){
2815  return;
2816  }
2817  sip = &Ship_info[shipp->ship_info_index];
2818 
2819  // already tst
2820  if(tst){
2821  return;
2822  }
2823 
2824  tst_pos = objp->pos;
2825  if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2826  tst_big = 1;
2827  }
2828  tst = 3;
2829 }
2830 
2831 extern void render_shields();
2832 
2833 void player_repair_frame(float frametime)
2834 {
2835  if(MULTIPLAYER_MASTER){
2836  int idx;
2837  for(idx=0;idx<MAX_PLAYERS;idx++){
2838  net_player *np;
2839 
2840  np = &Net_players[idx];
2841 
2842  if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != NULL) && (Net_player->player_id != Net_players[idx].player_id) && (Net_players[idx].m_player != NULL) && (Net_players[idx].m_player->objnum >= 0) && (Net_players[idx].m_player->objnum < MAX_OBJECTS)){
2843 
2844  // don't rearm/repair if the player is dead or dying/departing
2846  ai_do_repair_frame(&Objects[Net_players[idx].m_player->objnum],&Ai_info[Ships[Objects[Net_players[idx].m_player->objnum].instance].ai_index],frametime);
2847  }
2848  }
2849  }
2850  }
2851 
2852  if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
2854  }
2855 }
2856 
2857 #define NUM_FRAMES_TEST 300
2858 #define NUM_MIXED_SOUNDS 16
2860 {
2861  static int framecount = 0;
2862  static int test_running = 0;
2863  static float test_time = 0.0f;
2864 
2865  static int snds[NUM_MIXED_SOUNDS];
2866  int i;
2867 
2868  if ( test_running ) {
2869  framecount++;
2870  test_time += frame_time;
2871  if ( framecount >= NUM_FRAMES_TEST ) {
2872  test_running = 0;
2873  nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
2874  for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2875  snd_stop(snds[i]);
2876  }
2877  }
2878 
2879  if ( Test_begin == 1 ) {
2880  framecount = 0;
2881  test_running = 1;
2882  test_time = 0.0f;
2883  Test_begin = 0;
2884 
2885  for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2886  snds[i] = -1;
2887 
2888  // start looping digital sounds
2889  for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2890  snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
2891  }
2892 
2893 
2894 }
2895 
2896 DCF(dcf_fov, "Change the field of view of the main camera")
2897 {
2898  camera *cam = Main_camera.getCamera();
2899  bool process = true;
2900  float value;
2901 
2902  if (dc_optional_string_either("help", "--help")) {
2903  dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
2904  process = false;
2905  }
2906 
2907  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2908  if(cam == NULL) {
2909  dc_printf("Camera unavailable.");
2910  } else {
2911  dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)\n", cam->get_fov());
2912  }
2913 
2914  process = false;
2915  }
2916 
2917  if ((cam == NULL) || (!process)) {
2918  return;
2919  }
2920 
2921  if (!dc_maybe_stuff_float(&value)) {
2922  // No value passed, use default
2924  } else {
2925  // Value passed, Clamp it to valid values
2926  if (value < 0.25f) {
2927  value = 0.25f;
2928  dc_printf("Zoom factor clamped to 0.25\n");
2929  } else if (value > 1.25f) {
2930  value = 1.25f;
2931  dc_printf("Zoom factor clamped to 1.25\n");
2932  } else {
2933  dc_printf("Zoom factor set to %6.3f\n", value);
2934  }
2935 
2936  cam->set_fov(value);
2937  }
2938 }
2939 
2940 
2941 DCF(framerate_cap, "Sets the framerate cap")
2942 {
2943  bool process = true;
2944 
2945  if (dc_optional_string_either("help", "--help")) {
2946  dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
2947  dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
2948  dc_printf("[n] must be from 1 to 120.\n");
2949  process = false;
2950  }
2951 
2952  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2953  if ( Framerate_cap ) {
2954  dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
2955  } else {
2956  dc_printf("There is no framerate cap currently active.\n");
2957  }
2958 
2959  process = false;
2960  }
2961 
2962  if (!process) {
2963  return;
2964  }
2965 
2966  if (!dc_maybe_stuff_int(&Framerate_cap)) {
2967  Framerate_cap = 0;
2968  }
2969 
2970  if ((Framerate_cap < 0) || (Framerate_cap > 120)) {
2971  dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n");
2972  Framerate_cap = 0;
2973  }
2974 
2975  if (Framerate_cap == 0) {
2976  dc_printf("Framerate cap disabled");
2977  } else {
2978  dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
2979  }
2980 }
2981 
2982 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
2984 
2986 {
2987  object *view_target;
2988 
2989  if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
2990  view_target = &Objects[Player_ai->target_objnum];
2991  else
2992  view_target = Player_obj;
2993 
2994  if (Game_mode & GM_DEAD) {
2995  if (Player_ai->target_objnum != -1)
2996  view_target = &Objects[Player_ai->target_objnum];
2997  }
2998 
2999  if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3000  if (view_target != Player_obj){
3001 
3002  char view_target_name[128] = "";
3003  switch(Objects[Player_ai->target_objnum].type) {
3004  case OBJ_SHIP:
3006  strcpy_s(view_target_name, "targeted ship");
3007  } else {
3009  }
3010  break;
3011  case OBJ_WEAPON:
3013  Viewer_mode &= ~VM_OTHER_SHIP;
3014  break;
3015  case OBJ_JUMP_NODE: {
3016  strcpy_s(view_target_name, XSTR( "jump node", 184));
3017  Viewer_mode &= ~VM_OTHER_SHIP;
3018  break;
3019  }
3020  case OBJ_DEBRIS: {
3021  strcpy_s(view_target_name, "Debris");
3022  Viewer_mode &= ~VM_OTHER_SHIP;
3023  break;
3024  }
3025 
3026  default:
3027  Int3();
3028  break;
3029  }
3030 
3031  end_string_at_first_hash_symbol(view_target_name);
3032  if ( strlen(view_target_name) ) {
3034  HUD_fixed_printf(0.0f, gr_screen.current_color, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3035  Show_viewing_from_self = 1;
3036  }
3037  } else {
3038  color col;
3039  gr_init_color(&col, 0, 255, 0);
3041  HUD_fixed_printf(2.0f, col, XSTR( "Viewing from observer\n", 187));
3042  Show_viewing_from_self = 1;
3043  } else {
3044  if (Show_viewing_from_self)
3045  HUD_fixed_printf(2.0f, col, XSTR( "Viewing from self\n", 188));
3046  }
3047  }
3048  }
3049 
3050  Last_view_target = view_target;
3051 }
3052 
3053 
3054 float Game_hit_x = 0.0f;
3055 float Game_hit_y = 0.0f;
3056 
3057 // Reset at the beginning of each frame
3059 {
3060  Game_hit_x = 0.0f;
3061  Game_hit_y = 0.0f;
3062 }
3063 
3064 // Apply a 2d whack to the player
3065 void game_whack_apply( float x, float y )
3066 {
3067  // Do some force feedback
3068  joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3069 
3070  // Move the eye
3071  Game_hit_x += x;
3072  Game_hit_y += y;
3073 
3074 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3075 }
3076 
3077 // call to apply a "shudder"
3078 void game_shudder_apply(int time, float intensity)
3079 {
3080  Game_shudder_time = timestamp(time);
3081  Game_shudder_total = time;
3082  Game_shudder_intensity = intensity;
3083 }
3084 
3085 float get_shake(float intensity, int decay_time, int max_decay_time)
3086 {
3087  int r = myrand();
3088 
3089  float shake = intensity * (float)(r-RAND_MAX_2) * RAND_MAX_1f;
3090 
3091  if (decay_time >= 0) {
3092  Assert(max_decay_time > 0);
3093  shake *= (0.5f - fl_abs(0.5f - (float) decay_time / (float) max_decay_time));
3094  }
3095 
3096  return shake;
3097 }
3098 
3099 #define FF_SCALE 10000
3100 extern int Wash_on;
3101 extern float sn_shudder;
3103 {
3104  angles tangles;
3105  tangles.p = 0.0f;
3106  tangles.h = 0.0f;
3107  tangles.b = 0.0f;
3108 
3109  // do shakes that only affect the HUD
3110  if (Viewer_obj == Player_obj) {
3112 
3113  // Make eye shake due to afterburner
3117  }
3118 
3119  // Make eye shake due to engine wash
3120  if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3121  float wash_intensity = Ships[Player_obj->instance].wash_intensity;
3122 
3123  tangles.p += get_shake(0.07f * wash_intensity, -1, 0);
3124  tangles.h += get_shake(0.07f * wash_intensity, -1, 0);
3125 
3126  // play the force feedback effect
3127  vec3d rand_vec;
3128  vm_vec_rand_vec_quick(&rand_vec);
3129  joy_ff_play_dir_effect(FF_SCALE * wash_intensity * rand_vec.xyz.x, FF_SCALE * wash_intensity * rand_vec.xyz.y);
3130  }
3131 
3132  // Make eye shake due to shuddering
3133  if (Game_shudder_time != -1) {
3134  if (timestamp_elapsed(Game_shudder_time)) {
3135  Game_shudder_time = -1;
3136  } else {
3137  tangles.p += get_shake(Game_shudder_intensity * 0.005f, timestamp_until(Game_shudder_time), Game_shudder_total);
3138  tangles.h += get_shake(Game_shudder_intensity * 0.005f, timestamp_until(Game_shudder_time), Game_shudder_total);
3139  }
3140  }
3141  }
3142  // do shakes that affect external cameras
3143  else {
3144  // Make eye shake due to supernova
3145  if (supernova_camera_cut()) {
3146  float cut_pct = 1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME);
3147  tangles.p += get_shake(0.07f * cut_pct * sn_shudder, -1, 0);
3148  tangles.h += get_shake(0.07f * cut_pct * sn_shudder, -1, 0);
3149  }
3150  }
3151 
3152  // maybe bail
3153  if (tangles.p == 0.0f && tangles.h == 0.0f && tangles.b == 0.0f)
3154  return;
3155 
3156  matrix tm, tm2;
3157  vm_angles_2_matrix(&tm, &tangles);
3158  Assert(vm_vec_mag(&tm.vec.fvec) > 0.0f);
3159  Assert(vm_vec_mag(&tm.vec.rvec) > 0.0f);
3160  Assert(vm_vec_mag(&tm.vec.uvec) > 0.0f);
3161  vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3162  *eye_orient = tm2;
3163 }
3164 
3165 // Player's velocity just before he blew up. Used to keep camera target moving.
3166 vec3d Dead_player_last_vel = { { { 1.0f, 1.0f, 1.0f } } };
3167 
3168 extern float View_zoom;
3169 inline void render_environment(int i, vec3d *eye_pos, matrix *new_orient, float new_zoom)
3170 {
3172 
3173  gr_clear();
3174 
3175  g3_set_view_matrix( eye_pos, new_orient, new_zoom );
3176 
3179 
3180  if ( Game_subspace_effect ) {
3181  stars_draw(0, 0, 0, 1, 1);
3182  } else {
3183  stars_draw(0, 1, 1, 0, 1);
3184  }
3185 
3188 }
3189 
3191 {
3192  matrix new_orient = IDENTITY_MATRIX;
3193  float old_zoom = View_zoom, new_zoom = 1.0f;//0.925f;
3194  int i = 0;
3195 
3196 
3197  if (Cmdline_nohtl)
3198  return;
3199 
3200  if(!cid.isValid())
3201  return;
3202 
3203  vec3d cam_pos;
3204  matrix cam_orient;
3205  cid.getCamera()->get_info(&cam_pos, &cam_orient);
3206 
3207  // prefer the mission specified envmap over the static-generated envmap, but
3208  // the dynamic envmap should always get preference if in a subspace mission
3209  if ( !Dynamic_environment && strlen(The_mission.envmap_name) ) {
3211 
3212  if (ENVMAP >= 0)
3213  return;
3214  }
3215 
3216  if (gr_screen.envmap_render_target < 0) {
3217  if (ENVMAP >= 0)
3218  return;
3219 
3220  if (strlen(The_mission.envmap_name)) {
3222 
3223  if (ENVMAP < 0)
3225  } else {
3227  }
3228 
3229  return;
3230  }
3231 
3233 
3234 /*
3235  Envmap matrix setup -- left-handed
3236  -------------------------------------------------
3237  Face -- Forward Up Right
3238  px +X +Y -Z
3239  nx -X +Y +Z
3240  py +Y -Z +X
3241  ny -Y +Z +X
3242  pz +Z +Y +X
3243  nz -Z +Y -X
3244 */
3245 
3246  // NOTE: OpenGL needs up/down reversed
3247 
3248  // face 1 (px / right)
3249  memset( &new_orient, 0, sizeof(matrix) );
3250  new_orient.vec.fvec.xyz.x = 1.0f;
3251  new_orient.vec.uvec.xyz.y = 1.0f;
3252  new_orient.vec.rvec.xyz.z = -1.0f;
3253  render_environment(i, &cam_pos, &new_orient, new_zoom);
3254  i++; // bump!
3255 
3256  // face 2 (nx / left)
3257  memset( &new_orient, 0, sizeof(matrix) );
3258  new_orient.vec.fvec.xyz.x = -1.0f;
3259  new_orient.vec.uvec.xyz.y = 1.0f;
3260  new_orient.vec.rvec.xyz.z = 1.0f;
3261  render_environment(i, &cam_pos, &new_orient, new_zoom);
3262  i++; // bump!
3263 
3264  // face 3 (py / up)
3265  memset( &new_orient, 0, sizeof(matrix) );
3266  new_orient.vec.fvec.xyz.y = (gr_screen.mode == GR_OPENGL) ? 1.0f : -1.0f;
3267  new_orient.vec.uvec.xyz.z = (gr_screen.mode == GR_OPENGL) ? -1.0f : 1.0f;
3268  new_orient.vec.rvec.xyz.x = 1.0f;
3269  render_environment(i, &cam_pos, &new_orient, new_zoom);
3270  i++; // bump!
3271 
3272  // face 4 (ny / down)
3273  memset( &new_orient, 0, sizeof(matrix) );
3274  new_orient.vec.fvec.xyz.y = (gr_screen.mode == GR_OPENGL) ? -1.0f : 1.0f;
3275  new_orient.vec.uvec.xyz.z = (gr_screen.mode == GR_OPENGL) ? 1.0f : -1.0f;
3276  new_orient.vec.rvec.xyz.x = 1.0f;
3277  render_environment(i, &cam_pos, &new_orient, new_zoom);
3278  i++; // bump!
3279 
3280  // face 5 (pz / forward)
3281  memset( &new_orient, 0, sizeof(matrix) );
3282  new_orient.vec.fvec.xyz.z = 1.0f;
3283  new_orient.vec.uvec.xyz.y = 1.0f;
3284  new_orient.vec.rvec.xyz.x = 1.0f;
3285  render_environment(i, &cam_pos, &new_orient, new_zoom);
3286  i++; // bump!
3287 
3288  // face 6 (nz / back)
3289  memset( &new_orient, 0, sizeof(matrix) );
3290  new_orient.vec.fvec.xyz.z = -1.0f;
3291  new_orient.vec.uvec.xyz.y = 1.0f;
3292  new_orient.vec.rvec.xyz.x = -1.0f;
3293  render_environment(i, &cam_pos, &new_orient, new_zoom);
3294 
3295 
3296  // we're done, so now reset
3298  g3_set_view_matrix( &cam_pos, &cam_orient, old_zoom );
3299 }
3300 
3301 // setup the render target ready for this mission's environment map
3303 {
3304  const int size = 512;
3305  int gen_flags = (BMP_FLAG_RENDER_TARGET_STATIC | BMP_FLAG_CUBEMAP);
3306 
3307  if ( !Cmdline_env ) {
3308  return;
3309  }
3310 
3311  if (gr_screen.envmap_render_target >= 0) {
3313  Warning(LOCATION, "Unable to release environment map render target.");
3314  }
3315 
3317  }
3318 
3320  Dynamic_environment = true;
3321  gen_flags &= ~BMP_FLAG_RENDER_TARGET_STATIC;
3322  gen_flags |= BMP_FLAG_RENDER_TARGET_DYNAMIC;
3323  }
3324  // bail if we are going to be static, and have an envmap specified already
3325  else if ( strlen(The_mission.envmap_name) ) {
3326  return;
3327  }
3328 
3329  gr_screen.envmap_render_target = bm_make_render_target(size, size, gen_flags);
3330 }
3331 
3333 
3335 {
3336  static camid chase_camera;
3337  if(!chase_camera.isValid())
3338  {
3339  chase_camera = cam_create("Chase camera");
3340  }
3341 
3342  return chase_camera;
3343 }
3344 
3345 extern vec3d Dead_camera_pos;
3346 
3347 // Set eye_pos and eye_orient based on view mode.
3349 {
3350  bool fov_changed;
3351 
3352  if(!Main_camera.isValid())
3353  {
3354  Main_camera = cam_create("Main camera");
3355  }
3356  camera *main_cam = Main_camera.getCamera();
3357  if(main_cam == NULL)
3358  {
3359  Error(LOCATION, "Unable to generate main camera");
3360  return camid();
3361  }
3362 
3363  vec3d eye_pos;
3365  vec3d tmp_dir;
3366 
3367  static int last_Viewer_mode = 0;
3368  static int last_Game_mode = 0;
3369  static int last_Viewer_objnum = -1;
3370  static float last_FOV = Sexp_fov;
3371 
3372  fov_changed = ((last_FOV != Sexp_fov) && (Sexp_fov > 0.0f));
3373 
3374  //First, make sure we take into account 2D Missions.
3375  //These replace the normal player in-cockpit view with a topdown view.
3377  {
3378  if(!Viewer_mode)
3379  {
3381  }
3382  }
3383 
3384  // This code is supposed to detect camera "cuts"... like going between
3385  // different views.
3386 
3387  // determine if we need to regenerate the nebula
3388  if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3389  ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3390  (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3391  ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3392  (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3393  ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3394  (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3395  ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3396  (!(last_Viewer_mode & VM_FREECAMERA) && (Viewer_mode & VM_FREECAMERA)) ||
3397  ((last_Viewer_mode & VM_FREECAMERA) && !(Viewer_mode & VM_FREECAMERA)) ||
3398  (!(last_Viewer_mode & VM_TOPDOWN) && (Viewer_mode & VM_TOPDOWN)) ||
3399  ((last_Viewer_mode & VM_TOPDOWN) && !(Viewer_mode & VM_TOPDOWN)) ||
3400  (fov_changed) ||
3401  ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3402  ) {
3403 
3404  // regenerate the nebula
3405  neb2_eye_changed();
3406  }
3407 
3408  if ( (last_Viewer_mode != Viewer_mode)
3409  || (last_Game_mode != Game_mode)
3410  || (fov_changed)
3411  || (Viewer_mode & VM_FREECAMERA)) {
3412  //mprintf(( "************** Camera cut! ************\n" ));
3413  last_Viewer_mode = Viewer_mode;
3414  last_Game_mode = Game_mode;
3415  last_FOV = main_cam->get_fov();
3416 
3417  // Camera moved. Tell stars & debris to not do blurring.
3418  stars_camera_cut();
3419  }
3420 
3421  say_view_target();
3422 
3423  if ( Viewer_mode & VM_PADLOCK_ANY ) {
3425  }
3426 
3427  if (Game_mode & GM_DEAD) {
3428  vec3d vec_to_deader, view_pos;
3429  float dist;
3430 
3432 
3433  if (Player_ai->target_objnum != -1) {
3434  int view_from_player = 1;
3435 
3436  if (Viewer_mode & VM_OTHER_SHIP) {
3437  // View from target.
3439 
3440  last_Viewer_objnum = Player_ai->target_objnum;
3441 
3442  if ( Viewer_obj->type == OBJ_SHIP ) {
3443  ship_get_eye( &eye_pos, &eye_orient, Viewer_obj );
3444  view_from_player = 0;
3445  }
3446  } else {
3447  last_Viewer_objnum = -1;
3448  }
3449 
3450  if(Viewer_obj)
3452  else
3453  Script_system.RemHookVar("Viewer");
3454 
3455  if ( view_from_player ) {
3456  // View target from player ship.
3457  Viewer_obj = NULL;
3458  eye_pos = Player_obj->pos;
3459  vm_vec_normalized_dir(&tmp_dir, &Objects[Player_ai->target_objnum].pos, &eye_pos);
3460  vm_vector_2_matrix(&eye_orient, &tmp_dir, NULL, NULL);
3461  //rtn_cid = ship_get_followtarget_eye( Player_obj );
3462  }
3463  } else {
3464  dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3465 
3466  if (dist < MIN_DIST_TO_DEAD_CAMERA)
3467  dist += flFrametime * 16.0f;
3468 
3469  vm_vec_scale(&vec_to_deader, -dist);
3470  vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3471 
3472  view_pos = Player_obj->pos;
3473 
3474  if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3475  Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3476  vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3477  Dead_player_last_vel = Player_obj->phys_info.vel;
3478  //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.x, Player_obj->phys_info.vel.y, Player_obj->phys_info.vel.z));
3479  } else if (Player_ai->target_objnum != -1) {
3480  view_pos = Objects[Player_ai->target_objnum].pos;
3481  } else {
3482  // Make camera follow explosion, but gradually slow down.
3483  vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3484  view_pos = Player_obj->pos;
3485  vm_vec_scale(&Dead_player_last_vel, 0.99f);
3486  vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, MIN(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3487  }
3488 
3489  eye_pos = Dead_camera_pos;
3490 
3491  vm_vec_normalized_dir(&tmp_dir, &Player_obj->pos, &eye_pos);
3492 
3493  vm_vector_2_matrix(&eye_orient, &tmp_dir, NULL, NULL);
3494  Viewer_obj = NULL;
3495  }
3496  }
3497 
3498  // if supernova shockwave
3499  if(supernova_camera_cut()){
3500  // no viewer obj
3501  Viewer_obj = NULL;
3502 
3503  // call it dead view
3505 
3506  // set eye pos and orient
3507  //rtn_cid = supernova_set_view();
3508  supernova_get_eye(&eye_pos, &eye_orient);
3509  } else {
3510  // If already blown up, these other modes can override.
3511  if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3512  Viewer_mode &= ~VM_DEAD_VIEW;
3513 
3514  if(!(Viewer_mode & VM_FREECAMERA))
3516 
3517  if (Viewer_mode & VM_OTHER_SHIP) {
3518  if (Player_ai->target_objnum != -1){
3520  last_Viewer_objnum = Player_ai->target_objnum;
3521  } else {
3522  Viewer_mode &= ~VM_OTHER_SHIP;
3523  last_Viewer_objnum = -1;
3524  }
3525  } else {
3526  last_Viewer_objnum = -1;
3527  }
3528 
3529  if(Viewer_mode & VM_FREECAMERA) {
3530  Viewer_obj = NULL;
3531  return cam_get_current();
3532  } else if (Viewer_mode & VM_EXTERNAL) {
3533  matrix tm, tm2;
3534 
3536  vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3537 
3539 
3540  vm_vec_sub(&tmp_dir, &Viewer_obj->pos, &eye_pos);
3541  vm_vec_normalize(&tmp_dir);
3542  vm_vector_2_matrix(&eye_orient, &tmp_dir, &Viewer_obj->orient.vec.uvec, NULL);
3543  Viewer_obj = NULL;
3544 
3545  // Modify the orientation based on head orientation.
3546  compute_slew_matrix(&eye_orient, &Viewer_slew_angles);
3547 
3548  } else if ( Viewer_mode & VM_CHASE ) {
3549  vec3d move_dir;
3550  vec3d aim_pt;
3551 
3552  if ( Viewer_obj->phys_info.speed < 62.5f )
3553  move_dir = Viewer_obj->phys_info.vel;
3554  else {
3555  move_dir = Viewer_obj->phys_info.vel;
3556  vm_vec_scale(&move_dir, (62.5f/Viewer_obj->phys_info.speed));
3557  }
3558 
3559  vec3d tmp_up;
3560  matrix eyemat;
3561  ship_get_eye(&tmp_up, &eyemat, Viewer_obj, false, false);
3562 
3563  //create a better 3rd person view if this is the player ship
3564  if (Viewer_obj==Player_obj)
3565  {
3566  //get a point 1000m forward of ship
3567  vm_vec_copy_scale(&aim_pt,&Viewer_obj->orient.vec.fvec,1000.0f);
3568  vm_vec_add2(&aim_pt,&Viewer_obj->pos);
3569 
3570  vm_vec_scale_add(&eye_pos, &Viewer_obj->pos, &move_dir, -0.02f * Viewer_obj->radius);
3571  vm_vec_scale_add2(&eye_pos, &eyemat.vec.fvec, -2.125f * Viewer_obj->radius - Viewer_chase_info.distance);
3572  vm_vec_scale_add2(&eye_pos, &eyemat.vec.uvec, 0.625f * Viewer_obj->radius + 0.35f * Viewer_chase_info.distance);
3573  vm_vec_sub(&tmp_dir, &aim_pt, &eye_pos);
3574  vm_vec_normalize(&tmp_dir);
3575  }
3576  else
3577  {
3578  vm_vec_scale_add(&eye_pos, &Viewer_obj->pos, &move_dir, -0.02f * Viewer_obj->radius);
3579  vm_vec_scale_add2(&eye_pos, &eyemat.vec.fvec, -2.5f * Viewer_obj->radius - Viewer_chase_info.distance);
3580  vm_vec_scale_add2(&eye_pos, &eyemat.vec.uvec, 0.75f * Viewer_obj->radius + 0.35f * Viewer_chase_info.distance);
3581  vm_vec_sub(&tmp_dir, &Viewer_obj->pos, &eye_pos);
3582  vm_vec_normalize(&tmp_dir);
3583  }
3584 
3585  // JAS: I added the following code because if you slew up using
3586  // Descent-style physics, tmp_dir and Viewer_obj->orient.vec.uvec are
3587  // equal, which causes a zero-length vector in the vm_vector_2_matrix
3588  // call because the up and the forward vector are the same. I fixed
3589  // it by adding in a fraction of the right vector all the time to the
3590  // up vector.
3591  tmp_up = eyemat.vec.uvec;
3592  vm_vec_scale_add2( &tmp_up, &eyemat.vec.rvec, 0.00001f );
3593 
3594  vm_vector_2_matrix(&eye_orient, &tmp_dir, &tmp_up, NULL);
3595  Viewer_obj = NULL;
3596 
3597  // Modify the orientation based on head orientation.
3598  compute_slew_matrix(&eye_orient, &Viewer_slew_angles);
3599  } else if ( Viewer_mode & VM_WARP_CHASE ) {
3600  Warp_camera.get_info(&eye_pos, NULL);
3601 
3603 
3604  vec3d warp_pos = Player_obj->pos;
3605  shipp->warpout_effect->getWarpPosition(&warp_pos);
3606  vm_vec_sub(&tmp_dir, &warp_pos, &eye_pos);
3607  vm_vec_normalize(&tmp_dir);
3608  vm_vector_2_matrix(&eye_orient, &tmp_dir, &Player_obj->orient.vec.uvec, NULL);
3609  Viewer_obj = NULL;
3610  } else if (Viewer_mode & VM_TOPDOWN) {
3611  angles rot_angles = { PI_2, 0.0f, 0.0f };
3612  bool position_override = false;
3613  if(Viewer_obj->type == OBJ_SHIP) {
3615  if(sip->topdown_offset_def) {
3616  eye_pos.xyz.x = Viewer_obj->pos.xyz.x + sip->topdown_offset.xyz.x;
3617  eye_pos.xyz.y = Viewer_obj->pos.xyz.y + sip->topdown_offset.xyz.y;
3618  eye_pos.xyz.z = Viewer_obj->pos.xyz.z + sip->topdown_offset.xyz.z;
3619  position_override = true;
3620  }
3621  }
3622  if(!position_override) {
3623  eye_pos.xyz.x = Viewer_obj->pos.xyz.x;
3624  eye_pos.xyz.y = Viewer_obj->pos.xyz.y + Viewer_obj->radius * 25.0f;
3625  eye_pos.xyz.z = Viewer_obj->pos.xyz.z;
3626  }
3627  vm_angles_2_matrix(&eye_orient, &rot_angles);
3628  Viewer_obj = NULL;
3629  } else {
3630  // get an eye position based upon the correct type of object
3631  switch(Viewer_obj->type){
3632  case OBJ_SHIP:
3633  // make a call to get the eye point for the player object
3634  ship_get_eye( &eye_pos, &eye_orient, Viewer_obj );
3635  break;
3636  case OBJ_OBSERVER:
3637  // make a call to get the eye point for the player object
3638  observer_get_eye( &eye_pos, &eye_orient, Viewer_obj );
3639  break;
3640  default :
3641  mprintf(("Invalid Value for Viewer_obj->type. Expected values are OBJ_SHIP (1) and OBJ_OBSERVER (12), we encountered %d. Please tell a coder.\n", Viewer_obj->type));
3642  Int3();
3643  }
3644 
3645  #ifdef JOHNS_DEBUG_CODE
3646  john_debug_stuff(&eye_pos, &eye_orient);
3647  #endif
3648  }
3649  }
3650  }
3651 
3652  main_cam->set_position(&eye_pos);
3653  main_cam->set_rotation(&eye_orient);
3654 
3655  // setup neb2 rendering
3657 
3658  return Main_camera;
3659 }
3660 
3661 #ifndef NDEBUG
3662 extern void ai_debug_render_stuff();
3663 #endif
3664 
3666 DCF_BOOL( subspace, Game_subspace_effect )
3667 
3669 
3670 // Does everything needed to render a frame
3671 extern SCP_vector<object*> effect_ships;
3672 extern SCP_vector<object*> transparent_objects;
3674 {
3675 
3676  g3_start_frame(game_zbuffer);
3677 
3678  camera *cam = cid.getCamera();
3679  matrix eye_no_jitter = vmd_identity_matrix;
3680  if(cam != NULL)
3681  {
3682  vec3d eye_pos;
3684 
3685  //Get current camera info
3686  cam->get_info(&eye_pos, &eye_orient);
3687 
3688  //Handle jitter if not cutscene camera
3689  eye_no_jitter = eye_orient;
3690  if( !(Viewer_mode & VM_FREECAMERA) ) {
3691  apply_view_shake(&eye_orient);
3692  cam->set_rotation(&eye_orient);
3693  }
3694 
3695  //Maybe override FOV from SEXP
3696  if(Sexp_fov <= 0.0f)
3697  g3_set_view_matrix(&eye_pos, &eye_orient, cam->get_fov());
3698  else
3699  g3_set_view_matrix(&eye_pos, &eye_orient, Sexp_fov);
3700  }
3701  else
3702  {
3704  }
3705 
3706  // maybe offset the HUD (jitter stuff) and measure the 2D displacement between the player's view and ship vector
3707  int dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3708  HUD_set_offsets(Viewer_obj, !dont_offset, &eye_no_jitter);
3709 
3710  // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3711  // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3712  // must be done before ships are rendered
3713  if ( MULTIPLAYER_CLIENT ) {
3715  }
3716 
3717  // this needs to happen after g3_start_frame() and before the primary projection and view matrix is setup
3718  // Note: environment mapping gets disabled when rendering to texture; if you change
3719  // this, make sure that the current render target gets restored right afterwards!
3720  if ( Cmdline_env && !Env_cubemap_drawn && gr_screen.rendering_to_texture == -1 ) {
3721  PROFILE("Environment Mapping", setup_environment_mapping(cid));
3722 
3723  if ( !Dynamic_environment ) {
3724  Env_cubemap_drawn = true;
3725  }
3726  }
3728 
3730 
3731  neb2_render_setup(cid);
3732 
3733 #ifndef DYN_CLIP_DIST
3734  if (!Cmdline_nohtl) {
3737  }
3738 #endif
3739 
3740  if ( Game_subspace_effect ) {
3741  stars_draw(0,0,0,1,0);
3742  } else {
3743  stars_draw(1,1,1,0,0);
3744  }
3745 
3746  PROFILE("Build Shadow Map", shadows_render_all(Proj_fov, &Eye_matrix, &Eye_position));
3747  PROFILE("Render Scene", obj_render_queue_all());
3748 
3749  render_shields();
3750 
3751  PROFILE("Trails", trail_render_all()); // render missilie trails after everything else.
3752  PROFILE("Particles", particle_render_all()); // render particles after everything else.
3753 
3754 #ifdef DYN_CLIP_DIST
3755  if(!Cmdline_nohtl)
3756  {
3761  }
3762 #endif
3763 
3764  beam_render_all(); // render all beam weapons
3765 
3766  // render nebula lightning
3767  nebl_render_all();
3768 
3769  // render local player nebula
3771 
3773 
3774  // render all ships with shader effects on them
3775  SCP_vector<object*>::iterator obji = effect_ships.begin();
3776  for(;obji != effect_ships.end();++obji)
3777  {
3778  obj_render(*obji);
3779  }
3780  effect_ships.clear();
3781 
3783 
3784  Shadow_override = true;
3785  //Draw the viewer 'cause we didn't before.
3786  //This is so we can change the minimum clipping distance without messing everything up.
3787  if ( Viewer_obj
3788  && (Viewer_obj->type == OBJ_SHIP)
3791  {
3794  }
3795 
3796 
3797 #ifndef NDEBUG
3799  extern void snd_spew_debug_info();
3801 #endif
3802 
3803  if(!Cmdline_nohtl)
3804  {
3807  }
3808 
3809  //Draw viewer cockpit
3810  if(Viewer_obj != NULL && Viewer_mode != VM_TOPDOWN && Ship_info[Ships[Viewer_obj->instance].ship_info_index].cockpit_model_num > 0)
3811  {
3814  }
3815 
3816  if (!Cmdline_nohtl) {
3819 
3820  // Do the sunspot
3821  game_sunspot_process(flFrametime);
3822 
3825  }
3826  Shadow_override = false;
3827  //================ END OF 3D RENDERING STUFF ====================
3828 
3829  PROFILE("Post Process", gr_scene_texture_end());
3830 
3831  extern int Multi_display_netinfo;
3832  if(Multi_display_netinfo){
3833  extern void multi_display_netinfo();
3835  }
3836 
3838 
3839 #ifndef NDEBUG
3840  do_timing_test(flFrametime);
3841 
3842  extern int OO_update_index;
3844 
3845  // test
3846  extern void oo_display();
3847  oo_display();
3848 #endif
3849 
3850  g3_end_frame();
3851 }
3852 
3853 //#define JOHNS_DEBUG_CODE 1
3854 
3855 #ifdef JOHNS_DEBUG_CODE
3856 void john_debug_stuff(vec3d *eye_pos, matrix *eye_orient)
3857 {
3858  //if ( keyd_pressed[KEY_LSHIFT] )
3859  {
3860  ship_subsys *tsys = Players[Player_num].targeted_subobject;
3861  if ( tsys ) {
3862  model_subsystem *turret = tsys->system_info;
3863 
3864  if (turret->type == SUBSYSTEM_TURRET ) {
3865  vec3d fvec, uvec;
3866  object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3867 
3868  ship_model_start(tobj);
3869 
3870  model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3871  model_find_world_dir(&fvec, &turret->turret_matrix.vec.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3872  model_find_world_dir(&uvec, &turret->turret_matrix.vec.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3873 
3874  vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3875 
3876  ship_model_stop(tobj);
3877 
3878  Viewer_obj = NULL;
3879  }
3880  }
3881 
3882  }
3883 }
3884 #endif
3885 
3886 extern int Player_dead_state;
3887 
3888 // Flip the page and time how long it took.
3890 {
3891  fix t1, t2,d;
3892  int t;
3893  t1 = timer_get_fixed_seconds();
3894  gr_flip();
3895  t2 = timer_get_fixed_seconds();
3896  d = t2 - t1;
3898  sprintf( transfer_text, NOX("%d MB/s"), (int)fixmuldiv(t,65,d) );
3899 }
3900 
3902 {
3903  //Do camera stuff
3904  //This is for the warpout cam
3905  if ( Player->control_mode != PCM_NORMAL )
3906  Warp_camera.do_frame(flFrametime);
3907 
3908  //Do ingame cutscenes stuff
3909  if(!Time_compression_locked)
3910  {
3911  cam_do_frame(flFrametime);
3912  }
3913  else
3914  {
3915  cam_do_frame(flRealframetime);
3916  }
3917 
3918  // blow ships up in multiplayer dogfight
3919  if( MULTIPLAYER_MASTER && (Net_player != NULL) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (f2fl(Missiontime) >= 2.0f) && !dogfight_blown){
3920  // blow up all non-player ships
3921  ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3922  ship *shipp;
3923  ship_info *sip;
3924  while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3925  // bogus
3926  if((moveup->objnum < 0) || (moveup->objnum >= MAX_OBJECTS) || (Objects[moveup->objnum].type != OBJ_SHIP) || (Objects[moveup->objnum].instance < 0) || (Objects[moveup->objnum].instance >= MAX_SHIPS) || (Ships[Objects[moveup->objnum].instance].ship_info_index < 0) || (Ships[Objects[moveup->objnum].instance].ship_info_index >= static_cast<int>(Ship_info.size()))){
3927  moveup = GET_NEXT(moveup);
3928  continue;
3929  }
3930  shipp = &Ships[Objects[moveup->objnum].instance];
3931  sip = &Ship_info[shipp->ship_info_index];
3932 
3933  // only blow up small ships
3934  if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) && (shipp->team == Iff_traitor) ){
3935  // function to simply explode a ship where it is currently at
3936  ship_self_destruct( &Objects[moveup->objnum] );
3937  }
3938 
3939  moveup = GET_NEXT(moveup);
3940  }
3941 
3942  dogfight_blown = 1;
3943  }
3944 
3945  // process AWACS stuff - do this first thing
3946  awacs_process();
3947 
3948  //Do autopilot stuff
3949  NavSystem_Do();
3950 
3951  // single player, set Player hits_this_frame to 0
3952  if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3953  Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3955  }
3956 
3957  // supernova
3959  if(supernova_active() >= 5){
3960  return;
3961  }
3962 
3963  // fire targeting lasers now so that
3964  // 1 - created this frame
3965  // 2 - collide this frame
3966  // 3 - render this frame
3967  // 4 - ignored and deleted next frame
3968  // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3969  // frame
3971 
3972  // do this here so that it works for multiplayer
3973  if ( Viewer_obj ) {
3974  // get viewer direction
3975  int viewer_direction = PHYSICS_VIEWER_REAR;
3976 
3977  if(Viewer_mode == 0){
3978  viewer_direction = PHYSICS_VIEWER_FRONT;
3979  }
3980  if(Viewer_mode & VM_PADLOCK_UP){
3981  viewer_direction = PHYSICS_VIEWER_UP;
3982  }
3983  else if(Viewer_mode & VM_PADLOCK_REAR){
3984  viewer_direction = PHYSICS_VIEWER_REAR;
3985  }
3986  else if(Viewer_mode & VM_PADLOCK_LEFT){
3987  viewer_direction = PHYSICS_VIEWER_LEFT;
3988  }
3989  else if(Viewer_mode & VM_PADLOCK_RIGHT){
3990  viewer_direction = PHYSICS_VIEWER_RIGHT;
3991  }
3992 
3993  physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3994  } else {
3996  }
3997 
3998  // evaluate mission departures and arrivals before we process all objects.
3999  if ( !(Game_mode & GM_MULTIPLAYER) || (MULTIPLAYER_MASTER && !multi_endgame_ending()) ) {
4000 
4001  // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
4002  // ships/wing packets.
4003  if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL))) {
4005  }
4006 
4007  // if we're an observer, move ourselves seperately from the standard physics
4008  if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
4009  obj_observer_move(flFrametime);
4010  }
4011 
4012  // move all the objects now
4013  PROFILE("Move Objects - Master", obj_move_all(flFrametime));
4014 
4016  }
4017 
4018  // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
4020 
4021  // do all interpolation now
4023  // client side processing of warping in effect stages
4024  multi_do_client_warp(flFrametime);
4025 
4026  // client side movement of an observer
4028  obj_observer_move(flFrametime);
4029  }
4030 
4031  // move all objects - does interpolation now as well
4032  PROFILE("Move Objects - Client", obj_move_all(flFrametime));
4033 
4034 
4035  }
4036 
4037  // only process the message queue when the player is "in" the game
4038  if ( !Pre_player_entry ){
4039  message_queue_process(); // process any messages send to the player
4040  }
4041 
4042  message_maybe_distort(); // maybe distort incoming message if comms damaged
4043  player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4044  player_process_pending_praise(); // maybe send off a delayed praise message to the player
4045  player_maybe_play_all_alone_msg(); // maybe tell the player he is all alone
4046 
4047  if(!(Game_mode & GM_STANDALONE_SERVER)){
4048  // process some stuff every frame (before frame is rendered)
4050 
4051  hud_update_frame(flFrametime); // update hud systems
4052 
4053  if (!physics_paused) {
4054  // Move particle system
4055  PROFILE("Move Particles", particle_move_all(flFrametime));
4056 
4057  // Move missile trails
4058  PROFILE("Move Trails", trail_move_all(flFrametime));
4059 
4060  // Flash the gun flashes
4061  shipfx_flash_do_frame(flFrametime);
4062 
4063  shockwave_move_all(flFrametime); // update all the shockwaves
4064  }
4065 
4066  // subspace missile strikes
4067  ssm_process();
4068 
4069  obj_snd_do_frame(); // update the object-linked persistant sounds
4070 
4073 
4074 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4075 #ifndef NDEBUG
4076  if ( Game_subspace_effect ) {
4078  }
4079 #endif
4080  }
4081 
4083 }
4084 
4085 // Maybe render and process the dead-popup
4086 void game_maybe_do_dead_popup(float frametime)
4087 {
4088  if ( popupdead_is_active() ) {
4089  int leave_popup=1;
4090  int choice = popupdead_do_frame(frametime);
4091 
4092  if ( Game_mode & GM_NORMAL ) {
4093  switch(choice) {
4094  case 0:
4096  break;
4097 
4098  case 1:
4100  break;
4101 
4102  case 2:
4104  break;
4105 
4106  // this should only happen during a red alert mission
4107  case 3:
4109  {
4110  // choose the previous mission
4112  }
4113  else
4114  {
4115  // bogus?
4116  Int3();
4117  }
4118 
4120  break;
4121 
4122  default:
4123  leave_popup=0;
4124  break;
4125  }
4126  } else {
4127  switch( choice ) {
4128 
4131  break;
4132 
4133  case POPUPDEAD_DO_RESPAWN:
4136  break;
4137 
4138  case POPUPDEAD_DO_OBSERVER:
4141  break;
4142 
4143  default:
4144  leave_popup = 0;
4145  break;
4146  }
4147  }
4148 
4149  if ( leave_popup ) {
4150  popupdead_close();
4151  }
4152  }
4153 }
4154 
4155 // returns true if player is actually in a game_play stats
4157 {
4158  int state;
4159 
4160  state = gameseq_get_state();
4161  if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4162  return 0;
4163  else
4164  return 1;
4165 }
4166 
4168 {
4169  gr_reset_clip();
4170 
4171  if(cid.isValid()) {
4172  g3_start_frame(0); // 0 = turn zbuffering off
4173  g3_set_view( cid.getCamera() );
4174 
4175  hud_render_preprocess(flFrametime);
4176 
4177  g3_end_frame();
4178  }
4179 
4180  // main HUD rendering function
4181  hud_render_all();
4182 
4183  // Diminish the palette effect
4184  game_flash_diminish(flFrametime);
4185 }
4186 
4187 //100% blackness
4189 {
4190  Fade_type = FI_NONE;
4191  gr_create_shader(&Viewer_shader, 0, 0, 0, 0);
4192 }
4193 
4194 void game_shade_frame(float frametime)
4195 {
4196  // only do frame shade if we are actually in a game play state
4197  if ( !game_actually_playing() ) {
4198  return;
4199  }
4200 
4201  if (Fade_type != FI_NONE) {
4205 
4206  if( timestamp() >= Fade_start_timestamp ) {
4207  int startAlpha = 0;
4208  int endAlpha = 0;
4209 
4210  if (Fade_type == FI_FADEOUT) {
4211  endAlpha = 255;
4212  } else if (Fade_type == FI_FADEIN) {
4213  startAlpha = 255;
4214  }
4215 
4216  int alpha = 0;
4217 
4218  if( timestamp() < Fade_end_timestamp ) {
4219  int duration = (Fade_end_timestamp - Fade_start_timestamp);
4220  int elapsed = (timestamp() - Fade_start_timestamp);
4221 
4222  alpha = fl2i( (float)startAlpha + (((float)endAlpha - (float)startAlpha) / (float)duration) * (float)elapsed );
4223  } else {
4224  //Fade finished
4225  Fade_type = FI_NONE;
4227  Fade_end_timestamp = 0;
4228 
4229  alpha = endAlpha;
4230  }
4231 
4232  Viewer_shader.c = (ubyte)alpha;
4233  }
4234  }
4235 
4237 }
4238 
4239 const static int CUTSCENE_BAR_DIVISOR = 8;
4240 void bars_do_frame(float frametime)
4241 {
4243  {
4244  //Determine how far along we are
4245  Assert(Cutscene_delta_time > 0.0f);
4246 
4248  if(Cutscene_bars_progress >= 1.0f)
4249  {
4250  //Reset this stuff
4251  Cutscene_delta_time = 1.0f;
4252  Cutscene_bars_progress = 1.0f;
4253  }
4254 
4255  //Figure out where the bars should be
4256  int yborder;
4258  yborder = fl2i(Cutscene_bars_progress*(gr_screen.max_h/CUTSCENE_BAR_DIVISOR));
4259  else
4260  yborder = gr_screen.max_h/CUTSCENE_BAR_DIVISOR - fl2i(Cutscene_bars_progress*(gr_screen.max_h/CUTSCENE_BAR_DIVISOR));
4261 
4262  if (g3_in_frame() == 0) {
4263  //Set rectangles
4264  gr_set_color(0,0,0);
4265  gr_set_bitmap(0); // Valathil - Don't ask me why this has to be here but otherwise the black bars don't draw
4266  gr_rect(0, 0, gr_screen.max_w, yborder, GR_RESIZE_NONE);
4267  gr_rect(0, gr_screen.max_h-yborder, gr_screen.max_w, yborder, GR_RESIZE_NONE);
4268  } else {
4269  //Set clipping
4270  gr_reset_clip();
4271  gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2, GR_RESIZE_NONE );
4272  }
4273  }
4274  else if(Cutscene_bar_flags & CUB_CUTSCENE)
4275  {
4276  int yborder = gr_screen.max_h/CUTSCENE_BAR_DIVISOR;
4277 
4278  if (g3_in_frame() == 0) {
4279  gr_set_color(0,0,0);
4280  gr_set_bitmap(0); // Valathil - Don't ask me why this has to be here but otherwise the black bars don't draw
4281  gr_rect(0, 0, gr_screen.max_w, yborder, GR_RESIZE_NONE);
4282  gr_rect(0, gr_screen.max_h-yborder, gr_screen.max_w, yborder, GR_RESIZE_NONE);
4283  } else {
4284  gr_reset_clip();
4285  gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - (yborder*2), GR_RESIZE_NONE );
4286  }
4287  }
4288 }
4289 
4291  if(!Time_compression_locked) {
4292  // Player is dead
4293  game_set_view_clip(flFrametime);
4294 
4295  // Cutscene bars
4296  bars_do_frame(flRealframetime);
4297  } else {
4298  // Player is dead
4299  game_set_view_clip(flRealframetime);
4300 
4301  // Cutscene bars
4302  bars_do_frame(flRealframetime);
4303  }
4304 }
4305 
4306 //WMC - This does stuff like fading in and out and subtitles. Special FX?
4307 //Basically stuff you need rendered after everything else (including HUD)
4309 {
4310  float frametime = flFrametime;
4311  if(Time_compression_locked)
4312  {
4313  frametime = flRealframetime;
4314  }
4315 
4316  subtitles_do_frame(frametime);
4317  game_shade_frame(frametime);
4318  subtitles_do_frame_post_shaded(frametime);
4319 }
4320 
4321 #ifndef NDEBUG
4322 #define DEBUG_GET_TIME(x) { x = timer_get_fixed_seconds(); }
4323 #else
4324 #define DEBUG_GET_TIME(x)
4325 #endif
4326 
4327 void game_frame(bool paused)
4328 {
4329 #ifndef NDEBUG
4330  fix total_time1, total_time2;
4331  fix render2_time1=0, render2_time2=0;
4332  fix render3_time1=0, render3_time2=0;
4333  fix flip_time1=0, flip_time2=0;
4334  fix clear_time1=0, clear_time2=0;
4335 #endif
4336  int actually_playing;
4337 
4338 #ifndef NDEBUG
4339  if (Framerate_delay) {
4340  int start_time = timer_get_milliseconds();
4341  while (timer_get_milliseconds() < start_time + Framerate_delay)
4342  ;
4343  }
4344 #endif
4345  // start timing frame
4346  profile_begin("Main Frame");
4347 
4348  DEBUG_GET_TIME( total_time1 )
4349 
4350  if(paused)
4351  {
4352  // Reset the lights here or they just keep on increasing
4353  light_reset();
4354  }
4355  else
4356  {
4357  // var to hold which state we are in
4358  actually_playing = game_actually_playing();
4359 
4360  if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4361  if (!(Game_mode & GM_STANDALONE_SERVER)){
4362  Assert( OBJ_INDEX(Player_obj) >= 0 );
4363  }
4364  }
4365 
4367  Pre_player_entry = 0;
4368  } else {
4369  ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4370  }
4371 
4372  // Note: These are done even before the player enters, else buffers can overflow.
4373  if (! (Game_mode & GM_STANDALONE_SERVER)){
4374  radar_frame_init();
4375  }
4376 
4378 
4379  if ( !Pre_player_entry && actually_playing ) {
4380  if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4381 
4382  if( (!popup_running_state()) && (!popupdead_is_active()) ){
4384  read_player_controls( Player_obj, flFrametime);
4385  }
4386 
4387  // if we're not the master, we may have to send the server-critical ship status button_info bits
4390  }
4391  }
4392  }
4393 
4394  // Reset the whack stuff
4395  game_whack_reset();
4396 
4397  // These two lines must be outside of Pre_player_entry code,
4398  // otherwise too many lights are added.
4399  light_reset();
4400 
4401  if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4402  return;
4403  }
4404 
4405  PROFILE("Simulation", game_simulation_frame());
4406 
4407  // if not actually in a game play state, then return. This condition could only be true in
4408  // a multiplayer game.
4409  if (!actually_playing ) {
4410  Assert( Game_mode & GM_MULTIPLAYER );
4411  return;
4412  }
4413 
4414  }
4415 
4416  if (!Pre_player_entry) {
4417  if (! (Game_mode & GM_STANDALONE_SERVER)) {
4418  DEBUG_GET_TIME( clear_time1 )
4419  // clear the screen to black
4420  gr_reset_clip();
4422  gr_clear();
4423  }
4424 
4425  if(Player_obj)
4427  else
4428  Script_system.RemHookVar("Player");
4429 
4430  DEBUG_GET_TIME( clear_time2 )
4431  DEBUG_GET_TIME( render3_time1 )
4432 
4434 
4435  PROFILE("Render", game_render_frame( cid ));
4436 
4437  //Cutscene bars
4438  clip_frame_view();
4439 
4440  // save the eye position and orientation
4441  if ( Game_mode & GM_MULTIPLAYER ) {
4443  }
4444 
4445  Scripting_didnt_draw_hud = 1;
4448  Scripting_didnt_draw_hud = 0;
4449  Script_system.RemHookVar("Self");
4450 
4451  if(Scripting_didnt_draw_hud) {
4452  game_render_hud(cid);
4453  }
4454  HUD_reset_clip();
4455 
4456  if( (Game_detail_flags & DETAIL_FLAG_HUD) && (!(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) ) {
4457  anim_render_all(0, flFrametime);
4458  }
4459 
4462  {
4465  }
4466  Script_system.RemHookVar("Self");
4467 
4468  // check to see if we should display the death died popup
4469  if(Game_mode & GM_DEAD_BLEW_UP){
4470  if(Game_mode & GM_MULTIPLAYER){
4471  // catch the situation where we're supposed to be warping out on this transition
4475  } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4476  Player_died_popup_wait = -1;
4477  popupdead_start();
4478  }
4479  } else {
4480  if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4481  Player_died_popup_wait = -1;
4482  popupdead_start();
4483  }
4484  }
4485  }
4486 
4487  // Goober5000 - check if we should red-alert
4488  // (this is approximately where the red_alert_check_status() function tree began in the pre-HUD-overhaul code)
4490 
4491  DEBUG_GET_TIME( render3_time2 )
4492  DEBUG_GET_TIME( render2_time1 )
4493 
4494  gr_reset_clip();
4497  game_show_eye_pos(cid);
4498 
4500 
4501  gr_reset_clip();
4503 
4504  game_tst_frame();
4505 
4506  DEBUG_GET_TIME( render2_time2 )
4507 
4508  // maybe render and process the dead popup
4509  game_maybe_do_dead_popup(flFrametime);
4510 
4511  // If a regular popup is active, don't flip (popup code flips)
4512  if( !popup_running_state() ){
4513  DEBUG_GET_TIME( flip_time1 )
4514  PROFILE("Page Flip", game_flip_page_and_time_it());
4515  DEBUG_GET_TIME( flip_time2 )
4516  }
4517 
4518  } else {
4520  }
4521  }
4522 
4524  asteroid_frame();
4525 
4526  // process lightning (nebula only)
4527  nebl_process();
4528 
4529  profile_end("Main Frame");
4531 
4532  DEBUG_GET_TIME( total_time2 )
4533 
4534 #ifndef NDEBUG
4535  // Got some timing numbers
4536  Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4537  Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4538  Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4539  Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4540  Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4541 #endif
4542 
4543 }
4544 
4545 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4546  // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4547  // died. This resulted in screwed up death sequences.
4548 
4549 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4550 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4551 static int timer_paused=0;
4552 #if defined(TIMER_TEST) && !defined(NDEBUG)
4553 static int stop_count,start_count;
4554 static int time_stopped,time_started;
4555 #endif
4557 
4559 {
4561  return ;
4562  }
4563 
4564  // Last_time = timer_get_fixed_seconds();
4565  game_start_time();
4566  timestamp_reset();
4567  game_stop_time();
4568 }
4569 
4571 {
4572  if (timer_paused==0) {
4573  fix time;
4574  time = timer_get_fixed_seconds();
4575  // Save how much time progressed so far in the frame so we can
4576  // use it when we unpause.
4577  Last_delta_time = time - Last_time;
4578 
4579  //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4580  if (Last_delta_time < 0) {
4581  #if defined(TIMER_TEST) && !defined(NDEBUG)
4582  Int3(); //get Matt!!!!
4583  #endif
4584  Last_delta_time = 0;
4585  }
4586  #if defined(TIMER_TEST) && !defined(NDEBUG)
4587  time_stopped = time;
4588  #endif
4589 
4590  // Stop the timer_tick stuff...
4591  // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4592  saved_timestamp_ticker = timestamp_ticker;
4593  }
4594  timer_paused++;
4595 
4596  #if defined(TIMER_TEST) && !defined(NDEBUG)
4597  stop_count++;
4598  #endif
4599 }
4600 
4602 {
4603  timer_paused--;
4604  Assert(timer_paused >= 0);
4605  if (timer_paused==0) {
4606  fix time;
4607  time = timer_get_fixed_seconds();
4608  #if defined(TIMER_TEST) && !defined(NDEBUG)
4609  if (Last_time < 0)
4610  Int3(); //get Matt!!!!
4611  }
4612  #endif
4613  // Take current time, and set it backwards to account for time
4614  // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4615  // will be correct when it goes to calculate the frametime next
4616  // frame.
4617  Last_time = time - Last_delta_time;
4618  #if defined(TIMER_TEST) && !defined(NDEBUG)
4619  time_started = time;
4620  #endif
4621 
4622  // Restore the timer_tick stuff...
4623  // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4624  Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4626  saved_timestamp_ticker = -1;
4627  }
4628 
4629  #if defined(TIMER_TEST) && !defined(NDEBUG)
4630  start_count++;
4631  #endif
4632 }
4633 
4634 void lock_time_compression(bool is_locked)
4635 {
4636  Time_compression_locked = is_locked;
4637 }
4638 
4639 void change_time_compression(float multiplier)
4640 {
4641  fix modified = fl2f( f2fl(Game_time_compression) * multiplier );
4642 
4643  Desired_time_compression = Game_time_compression = modified;
4644  Time_compression_change_rate = 0;
4645 }
4646 
4647 void set_time_compression(float multiplier, float change_time)
4648 {
4649  if(change_time <= 0.0f)
4650  {
4651  Game_time_compression = Desired_time_compression = fl2f(multiplier);
4652  Time_compression_change_rate = 0;
4653  return;
4654  }
4655 
4656  Desired_time_compression = fl2f(multiplier);
4657  Time_compression_change_rate = fl2f( f2fl(Desired_time_compression - Game_time_compression) / change_time );
4658 }
4659 
4660 void game_set_frametime(int state)
4661 {
4662  fix thistime;
4663  float frame_cap_diff;
4664 
4665  thistime = timer_get_fixed_seconds();
4666 
4667  if ( Last_time == 0 )
4668  Frametime = F1_0 / 30;
4669  else
4670  Frametime = thistime - Last_time;
4671 
4672 // Frametime = F1_0 / 30;
4673 
4674 #ifndef NDEBUG
4675  fix debug_frametime = Frametime; // Just used to display frametime.
4676 #endif
4677 
4678  // If player hasn't entered mission yet, make frame take 1/4 second.
4679  if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4680  Frametime = F1_0/4;
4681 #ifndef NDEBUG
4682  else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4683 
4684  fix frame_speed = F1_0 / Debug_dump_frames;
4685 
4686  if (Frametime > frame_speed ){
4687  nprintf(("warning","slow frame: %x\n",(int)Frametime));
4688  } else {
4689  do {
4690  thistime = timer_get_fixed_seconds();
4691  Frametime = thistime - Last_time;
4692  } while (Frametime < frame_speed );
4693  }
4694  Frametime = frame_speed;
4695  }
4696 #endif
4697 
4698  Assertion( Framerate_cap > 0, "Framerate cap %d is too low. Needs to be a positive, non-zero number", Framerate_cap );
4699 
4700  // Cap the framerate so it doesn't get too high.
4701  if (!Cmdline_NoFPSCap)
4702  {
4703  fix cap;
4704 
4705  cap = F1_0/Framerate_cap;
4706  if (Frametime < cap) {
4707  thistime = cap - Frametime;
4708 // mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4709  Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4710  Frametime = cap;
4711  thistime = timer_get_fixed_seconds();
4712  }
4713  }
4714 
4715  if((Game_mode & GM_STANDALONE_SERVER) &&
4716  (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4717 
4718  frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4719  Sleep((DWORD)(frame_cap_diff*1000));
4720 
4721  thistime += fl2f((frame_cap_diff));
4722 
4723  Frametime = thistime - Last_time;
4724  }
4725 
4726  // If framerate is too low, cap it.
4727  if (Frametime > MAX_FRAMETIME) {
4728 #ifndef NDEBUG
4729  mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4730 #endif
4732  }
4733 
4734  flRealframetime = f2fl(Frametime);
4735 
4736  //Handle changes in time compression
4737  if(Game_time_compression != Desired_time_compression)
4738  {
4739  bool ascending = Desired_time_compression > Game_time_compression;
4740  if(Time_compression_change_rate)
4741  Game_time_compression += fixmul(Time_compression_change_rate, Frametime);
4742  if((ascending && Game_time_compression > Desired_time_compression)
4743  || (!ascending && Game_time_compression < Desired_time_compression))
4744  Game_time_compression = Desired_time_compression;
4745  }
4746 
4747  Frametime = fixmul(Frametime, Game_time_compression);
4748 
4749  if (Frametime <= 0)
4750  {
4751  // If the Frametime is zero or below due to Game_time_compression, set
4752  // the Frametime to 1 (1/65536 of a second).
4753  Frametime = 1;
4754  }
4755 
4756  Last_time = thistime;
4757  //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4759 
4760  flFrametime = f2fl(Frametime);
4761 
4762  auto frametime_ms = f2i(fixmul(Frametime, F1_0 * TIMESTAMP_FREQUENCY));
4763  timestamp_inc(frametime_ms);
4764 
4765  // wrap overall frametime if needed
4766  if ( FrametimeOverall > (INT_MAX - F1_0) )
4767  FrametimeOverall = 0;
4768 
4769  FrametimeOverall += Frametime;
4770 
4771 /* if ((Framecount > 0) && (Framecount < 10)) {
4772  mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4773  }
4774 */
4775 }
4776 
4778 {
4779  return FrametimeOverall;
4780 }
4781 
4782 // This is called from game_do_frame(), and from navmap_do_frame()
4784 {
4785  // TODO JAS: Put in if and move this into game_set_frametime,
4786  // fix navmap to call game_stop/start_time
4787  //if ( !timer_paused )
4789 }
4790 
4792 {
4795 
4796 // if (Player_ship->flags & SF_DYING)
4797 // flFrametime /= 15.0;
4798 
4801  }
4802 
4803  if ( game_single_step && (last_single_step == game_single_step) ) {
4804  os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4805  while( key_checkch() == 0 )
4806  os_sleep(10);
4807  os_set_title( XSTR( "FreeSpace", 171) );
4809  }
4810 
4811  last_single_step = game_single_step;
4812 
4814  Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4815  }
4816  game_frame();
4817 
4818  Keep_mouse_centered = 0;
4819  monitor_update(); // Update monitor variables
4820 }
4821 
4823 {
4825  game_do_frame();
4826  }
4827 }
4828 
4830 
4831 // Flush all input devices
4833 {
4834  key_flush();
4835  mouse_flush();
4836  joy_flush();
4837  snazzy_flush();
4838 
4839  Joymouse_button_status = 0;
4840 
4841  //mprintf(("Game flush!\n" ));
4842 }
4843 
4844 // function for multiplayer only which calls game_do_state_common() when running the
4845 // debug console
4847 {
4849 
4851 }
4852 
4853 // Call this whenever in a loop, or when you need to check for a keystroke.
4855 {
4856  int k;
4857 
4858  k = game_poll();
4859 
4860  // convert keypad enter to normal enter
4861  if ((k & KEY_MASK) == KEY_PADENTER)
4862  k = (k & ~KEY_MASK) | KEY_ENTER;
4863 
4864  return k;
4865 }
4866 
4867 // same as game_check_key(), except this is used while actually in the game. Since there
4868 // generally are differences between game control keys and general UI keys, makes sense to
4869 // have seperate functions for each case. If you are not checking a game control while in a
4870 // mission, you should probably be using game_check_key() instead.
4872 {
4873  int k, state;
4874 
4876  {
4877  if (!os_foreground()) {
4878  game_stop_time();
4879  os_sleep(1);
4880  game_start_time();
4881 
4882  // If we're in a single player game, pause it.
4883  if (!(Game_mode & GM_MULTIPLAYER)){
4886  }
4887  }
4888  }
4889  }
4890 
4891  k = key_inkey();
4892 
4893  // Move the mouse cursor with the joystick.
4894  if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4895  // Move the mouse cursor with the joystick
4896  int mx, my, dx, dy;
4897  int jx, jy, jz, jr;
4898 
4899  joy_get_pos( &jx, &jy, &jz, &jr );
4900 
4901  dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4902  dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4903 
4904  if ( dx || dy ) {
4905  mouse_get_real_pos( &mx, &my );
4906  mouse_set_pos( mx+dx, my+dy );
4907  }
4908 
4909  int j, m;
4910  j = joy_down(0);
4912 
4913  if ( j != Joymouse_button_status ) {
4914  //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4915  Joymouse_button_status = j;
4916  if ( j && (!m) ) {
4918  } else if ( (!j) && (m) ) {
4920  }
4921  }
4922  }
4923 
4924  // if we should be ignoring keys because of some multiplayer situations
4926  return 0;
4927  }
4928 
4929  state = gameseq_get_state();
4930 
4931  // If a popup is running, don't process all the Fn keys
4932  if( popup_active()) {
4933  if (state != GS_STATE_DEATH_BLEW_UP) {
4934  return k;
4935  }
4936  }
4937 
4938 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4939 
4940  switch (k) {
4941  case KEY_DEBUGGED + KEY_BACKSP:
4942  if(!(Game_mode & GM_MULTIPLAYER))
4943  {
4945  k = 0;
4946  }
4947  break;
4948 
4949  case KEY_F1:
4951  k = 0;
4952  break;
4953 
4954  case KEY_F2:
4955 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4956 
4957  // don't allow f2 while warping out in multiplayer
4958  if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4959  break;
4960  }
4961 
4962  switch (state) {
4964  case GS_STATE_OPTIONS_MENU:
4965  case GS_STATE_HUD_CONFIG:
4967  case GS_STATE_DEATH_DIED:
4968 // case GS_STATE_DEATH_BLEW_UP: // DEATH_BLEW_UP might be okay but do not comment out DEATH_DIED as otherwise no clean up is performed on the dead ship
4969  case GS_STATE_VIEW_MEDALS:
4970  break;
4971 
4972  default:
4974  k = 0;
4975  break;
4976  }
4977 
4978  break;
4979 
4980  // hotkey selection screen -- only valid from briefing and beyond.
4981  case KEY_F3:
4982  if ( (state == GS_STATE_TEAM_SELECT) || (state == GS_STATE_BRIEFING) || (state == GS_STATE_SHIP_SELECT) || (state == GS_STATE_WEAPON_SELECT) || (state == GS_STATE_GAME_PLAY) || (state == GS_STATE_GAME_PAUSED) ) {
4984  k = 0;
4985  }
4986  break;
4987 
4988  case KEY_DEBUGGED + KEY_F3:
4990  break;
4991 
4992  case KEY_F4:
4993  if(Game_mode & GM_MULTIPLAYER){
4994  if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4996  k = 0;
4997  }
4998  } else {
4999  if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
5001  k = 0;
5002  }
5003  }
5004  break;
5005 
5006  case KEY_ESC | KEY_SHIFTED:
5007  // make sure to quit properly out of multiplayer
5008  if(Game_mode & GM_MULTIPLAYER){
5010  }
5011 
5013  k = 0;
5014 
5015  break;
5016 
5017  case KEY_DEBUGGED + KEY_P:
5018  break;
5019 
5020  case KEY_PRINT_SCRN:
5021  {
5022  static int counter = os_config_read_uint(NULL, "ScreenshotNum", 0);
5023  char tmp_name[MAX_FILENAME_LEN];
5024 
5025  game_stop_time();
5026 
5027  // we could probably go with .3 here for 1,000 shots but people really need to clean out
5028  // their directories better than that so it's 100 for now.
5029  sprintf( tmp_name, NOX("screen%.4i"), counter );
5030  counter++;
5031 
5032  // we've got two character precision so we can only have 100 shots at a time, reset if needed
5033  //Now we have four digit precision :) -WMC
5034  if (counter > 9999)
5035  {
5036  //This should pop up a dialogue or something ingame.
5037  Warning(LOCATION, "Screenshot count has reached max of 9999. Resetting to 0.");
5038  counter = 0;
5039  }
5040 
5041  mprintf(( "Dumping screen to '%s'\n", tmp_name ));
5042  gr_print_screen(tmp_name);
5043 
5044  game_start_time();
5045  os_config_write_uint(NULL, "ScreenshotNum", counter);
5046  }
5047 
5048  k = 0;
5049  break;
5050 
5051  case KEY_SHIFTED | KEY_ENTER: {
5052 
5053 #if !defined(NDEBUG)
5054 
5055  if ( Game_mode & GM_NORMAL ){
5056  game_stop_time();
5057  }
5058 
5059  // if we're in multiplayer mode, do some special networking
5060  if(Game_mode & GM_MULTIPLAYER){
5062  } else {
5063  debug_console();
5064  }
5065 
5066  game_flush();
5067 
5068  if ( Game_mode & GM_NORMAL )
5069  game_start_time();
5070 
5071 #endif
5072 
5073  break;
5074  }
5075  }
5076 
5077  return k;
5078 }
5079 
5080 void os_close()
5081 {
5083 }
5084 
5085 // All code to process events. This is the only place
5086 // that you should change the state of the game.
5087 void game_process_event( int current_state, int event )
5088 {
5089  mprintf(("Got event %s (%d) in state %s (%d)\n", GS_event_text[event], event, GS_state_text[current_state], current_state));
5090 
5091  switch (event) {
5094  break;
5095 
5096  case GS_EVENT_MAIN_MENU:
5098  break;
5099 
5100  case GS_EVENT_OPTIONS_MENU:
5102  break;
5103 
5106  break;
5107 
5108  case GS_EVENT_TECH_MENU:
5110  break;
5111  case GS_EVENT_LAB:
5113  break;
5116  break;
5117 
5118  case GS_EVENT_START_GAME:
5119  Select_default_ship = 0;
5121  break;
5122 
5124  Select_default_ship = 1;
5126  break;
5127 
5128  case GS_EVENT_CMD_BRIEF:
5130  break;
5131 
5132  case GS_EVENT_RED_ALERT:
5134  break;
5135 
5138  break;
5139 
5140  case GS_EVENT_DEBRIEF:
5141  // did we end the campaign in the main freespace 2 single player campaign?
5142  // (specifically, did we successfully jump out when the supernova was in progress
5143  // and the campaign was ending?)
5144  if (Campaign_ending_via_supernova && (Game_mode & GM_CAMPAIGN_MODE)/* && !stricmp(Campaign.filename, "freespace2")*/) {
5146  } else {
5148  }
5149  break;
5150