2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
18 * Revision 1.40 2005/10/01 21:40:38 taylor
19 * deal with OS X apps a little better, sets the path only based on ".app" in the name rather than the name itself
20 * make sure a global cmdline.cfg file works with OS X when built as an app
22 * Revision 1.39 2005/08/12 08:57:20 taylor
23 * don't show hardware S-RAM value on HUD in debug
24 * do show in use GL texture memory
25 * have an actual fade effect for the credits screen artwork
27 * Revision 1.38 2004/09/20 01:31:44 theoddone33
30 * Revision 1.37 2004/07/04 11:31:43 taylor
31 * amd64 support, compiler warning fixes, don't use software rendering
33 * Revision 1.36 2004/06/12 01:11:35 taylor
34 * x86 compile fixes for OSX patch
36 * Revision 1.35 2004/06/11 00:53:02 tigital
37 * OSX: .app name, casts for gcc
39 * Revision 1.34 2003/08/09 03:18:03 taylor
40 * fix tips popup not having any tips
42 * Revision 1.33 2003/08/03 15:57:00 taylor
43 * simpler mouse usage; default ini settings in os_init(); cleanup
45 * Revision 1.32 2003/06/19 11:51:41 taylor
46 * adjustments to memory leak fixes
48 * Revision 1.31 2003/06/11 18:30:32 taylor
51 * Revision 1.30 2003/06/03 04:00:39 taylor
52 * Polish language support (Janusz Dziemidowicz)
54 * Revision 1.29 2003/05/25 02:30:42 taylor
57 * Revision 1.28 2003/05/18 03:55:30 taylor
58 * automatic language selection support
60 * Revision 1.27 2003/03/03 04:54:44 theoddone33
61 * Commit Taylor's ShowFPS fix
63 * Revision 1.26 2003/02/20 17:41:07 theoddone33
64 * Userdir patch from Taylor Richards
66 * Revision 1.25 2003/01/30 19:54:10 relnev
67 * ini config option for the frames per second counter (Taylor Richards)
69 * Revision 1.24 2002/08/31 01:39:13 theoddone33
70 * Speed up the renderer a tad
72 * Revision 1.23 2002/08/04 02:31:00 relnev
73 * make numlock not overlap with pause
75 * Revision 1.22 2002/08/02 23:07:03 relnev
76 * don't access the mouse in standalone mode
78 * Revision 1.21 2002/07/28 05:05:08 relnev
79 * removed some old stuff
81 * Revision 1.20 2002/07/24 00:20:41 relnev
84 * Revision 1.19 2002/06/17 06:33:08 relnev
85 * ryan's struct patch for gcc 2.95
87 * Revision 1.18 2002/06/16 04:46:33 relnev
88 * set up correct checksums for demo
90 * Revision 1.17 2002/06/09 04:41:17 relnev
91 * added copyright header
93 * Revision 1.16 2002/06/09 03:16:04 relnev
96 * removed unneeded asm, old sdl 2d setup.
98 * fixed crash caused by opengl_get_region.
100 * Revision 1.15 2002/06/05 08:05:28 relnev
101 * stub/warning removal.
103 * reworked the sound code.
105 * Revision 1.14 2002/06/05 04:03:32 relnev
106 * finished cfilesystem.
108 * removed some old code.
110 * fixed mouse save off-by-one.
114 * Revision 1.13 2002/06/02 04:26:34 relnev
117 * Revision 1.12 2002/06/02 00:31:35 relnev
118 * implemented osregistry
120 * Revision 1.11 2002/06/01 09:00:34 relnev
121 * silly debug memmanager
123 * Revision 1.10 2002/06/01 07:12:32 relnev
124 * a few NDEBUG updates.
126 * removed a few warnings.
128 * Revision 1.9 2002/05/31 03:05:59 relnev
131 * Revision 1.8 2002/05/29 02:52:32 theoddone33
132 * Enable OpenGL renderer
134 * Revision 1.7 2002/05/28 08:52:03 relnev
135 * implemented two assembly stubs.
137 * cleaned up a few warnings.
139 * added a little demo hackery to make it progress a little farther.
141 * Revision 1.6 2002/05/28 06:28:20 theoddone33
142 * Filesystem mods, actually reads some data files now
144 * Revision 1.5 2002/05/28 04:07:28 theoddone33
145 * New graphics stubbing arrangement
147 * Revision 1.4 2002/05/27 22:46:52 theoddone33
148 * Remove more undefined symbols
150 * Revision 1.3 2002/05/26 23:31:18 relnev
151 * added a few files that needed to be compiled
153 * freespace.cpp: now compiles
155 * Revision 1.2 2002/05/07 03:16:44 theoddone33
156 * The Great Newline Fix
158 * Revision 1.1.1.1 2002/05/03 03:28:09 root
162 * 201 6/16/00 3:15p Jefff
163 * sim of the year dvd version changes, a few german soty localization
166 * 200 11/03/99 11:06a Jefff
169 * 199 10/26/99 5:07p Jamest
170 * fixed jeffs dumb debug code
172 * 198 10/25/99 5:53p Jefff
173 * call control_config_common_init() on startup
175 * 197 10/14/99 10:18a Daveb
176 * Fixed incorrect CD checking problem on standalone server.
178 * 196 10/13/99 9:22a Daveb
179 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
180 * related to movies. Fixed launcher spawning from PXO screen.
182 * 195 10/06/99 11:05a Jefff
183 * new oem upsell 3 hotspot coords
185 * 194 10/06/99 10:31a Jefff
188 * 193 10/01/99 9:10a Daveb
191 * 192 9/15/99 4:57a Dave
192 * Updated ships.tbl checksum
194 * 191 9/15/99 3:58a Dave
195 * Removed framerate warning at all times.
197 * 190 9/15/99 3:16a Dave
198 * Remove mt-011.fs2 from the builtin mission list.
200 * 189 9/15/99 1:45a Dave
201 * Don't init joystick on standalone. Fixed campaign mode on standalone.
202 * Fixed no-score-report problem in TvT
204 * 188 9/14/99 6:08a Dave
205 * Updated (final) single, multi, and campaign list.
207 * 187 9/14/99 3:26a Dave
208 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
209 * respawn-too-early problem. Made a few crash points safe.
211 * 186 9/13/99 4:52p Dave
214 * 185 9/12/99 8:09p Dave
215 * Fixed problem where skip-training button would cause mission messages
216 * not to get paged out for the current mission.
218 * 184 9/10/99 11:53a Dave
219 * Shutdown graphics before sound to eliminate apparent lockups when
220 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
222 * 183 9/09/99 11:40p Dave
223 * Handle an SDL_assert() in beam code. Added supernova sounds. Play the right
224 * 2 end movies properly, based upon what the player did in the mission.
226 * 182 9/08/99 10:29p Dave
227 * Make beam sound pausing and unpausing much safer.
229 * 181 9/08/99 10:01p Dave
230 * Make sure game won't run in a drive's root directory. Make sure
231 * standalone routes suqad war messages properly to the host.
233 * 180 9/08/99 3:22p Dave
234 * Updated builtin mission list.
236 * 179 9/08/99 12:01p Jefff
237 * fixed Game_builtin_mission_list typo on Training-2.fs2
239 * 178 9/08/99 9:48a Andsager
240 * Add force feedback for engine wash.
242 * 177 9/07/99 4:01p Dave
243 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
244 * does everything properly (setting up address when binding). Remove
245 * black rectangle background from UI_INPUTBOX.
247 * 176 9/13/99 2:40a Dave
248 * Comment in full 80 minute CD check for RELEASE_REAL builds.
250 * 175 9/06/99 6:38p Dave
251 * Improved CD detection code.
253 * 174 9/06/99 1:30a Dave
254 * Intermediate checkin. Started on enforcing CD-in-drive to play the
257 * 173 9/06/99 1:16a Dave
258 * Make sure the user sees the intro movie.
260 * 172 9/04/99 8:00p Dave
261 * Fixed up 1024 and 32 bit movie support.
263 * 171 9/03/99 1:32a Dave
264 * CD checking by act. Added support to play 2 cutscenes in a row
265 * seamlessly. Fixed super low level cfile bug related to files in the
266 * root directory of a CD. Added cheat code to set campaign mission # in
269 * 170 9/01/99 10:49p Dave
270 * Added nice SquadWar checkbox to the client join wait screen.
272 * 169 9/01/99 10:14a Dave
275 * 168 8/29/99 4:51p Dave
276 * Fixed damaged checkin.
278 * 167 8/29/99 4:18p Andsager
279 * New "burst" limit for friendly damage. Also credit more damage done
280 * against large friendly ships.
282 * 166 8/27/99 6:38p Alanl
283 * crush the blasted repeating messages bug
285 * 164 8/26/99 9:09p Dave
286 * Force framerate check in everything but a RELEASE_REAL build.
288 * 163 8/26/99 9:45a Dave
289 * First pass at easter eggs and cheats.
291 * 162 8/24/99 8:55p Dave
292 * Make sure nondimming pixels work properly in tech menu.
294 * 161 8/24/99 1:49a Dave
295 * Fixed client-side afterburner stuttering. Added checkbox for no version
296 * checking on PXO join. Made button info passing more friendly between
299 * 160 8/22/99 5:53p Dave
300 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
301 * instead of ship designations for multiplayer players.
303 * 159 8/22/99 1:19p Dave
304 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
305 * which d3d cards are detected.
307 * 158 8/20/99 2:09p Dave
308 * PXO banner cycling.
310 * 157 8/19/99 10:59a Dave
311 * Packet loss detection.
313 * 156 8/19/99 10:12a Alanl
314 * preload mission-specific messages on machines greater than 48MB
316 * 155 8/16/99 4:04p Dave
317 * Big honking checkin.
319 * 154 8/11/99 5:54p Dave
320 * Fixed collision problem. Fixed standalone ghost problem.
322 * 153 8/10/99 7:59p Jefff
325 * 152 8/10/99 6:54p Dave
326 * Mad optimizations. Added paging to the nebula effect.
328 * 151 8/10/99 3:44p Jefff
329 * loads Intelligence information on startup
331 * 150 8/09/99 3:47p Dave
332 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
333 * non-nebula missions.
335 * 149 8/09/99 2:21p Andsager
336 * Fix patching from multiplayer direct to launcher update tab.
338 * 148 8/09/99 10:36a Dave
339 * Version info for game.
341 * 147 8/06/99 9:46p Dave
342 * Hopefully final changes for the demo.
344 * 146 8/06/99 3:34p Andsager
345 * Make title version info "(D)" -> "D" show up nicely
347 * 145 8/06/99 2:59p Adamp
348 * Fixed NT launcher/update problem.
350 * 144 8/06/99 1:52p Dave
351 * Bumped up MAX_BITMAPS for the demo.
353 * 143 8/06/99 12:17p Andsager
354 * Demo: down to just 1 demo dog
356 * 142 8/05/99 9:39p Dave
357 * Yet another new checksum.
359 * 141 8/05/99 6:19p Dave
360 * New demo checksums.
362 * 140 8/05/99 5:31p Andsager
363 * Up demo version 1.01
365 * 139 8/05/99 4:22p Andsager
366 * No time limit on upsell screens. Reverse order of display of upsell
369 * 138 8/05/99 4:17p Dave
370 * Tweaks to client interpolation.
372 * 137 8/05/99 3:52p Danw
374 * 136 8/05/99 3:01p Danw
376 * 135 8/05/99 2:43a Anoop
377 * removed duplicate definition.
379 * 134 8/05/99 2:13a Dave
382 * 133 8/05/99 2:05a Dave
385 * 132 8/05/99 1:22a Andsager
388 * 131 8/04/99 9:51p Andsager
389 * Add title screen to demo
391 * 130 8/04/99 6:47p Jefff
392 * fixed link error resulting from #ifdefs
394 * 129 8/04/99 6:26p Dave
395 * Updated ship tbl checksum.
397 * 128 8/04/99 5:40p Andsager
398 * Add multiple demo dogs
400 * 127 8/04/99 5:36p Andsager
401 * Show upsell screens at end of demo campaign before returning to main
404 * 126 8/04/99 11:42a Danw
405 * tone down EAX reverb
407 * 125 8/04/99 11:23a Dave
408 * Updated demo checksums.
410 * 124 8/03/99 11:02p Dave
411 * Maybe fixed sync problems in multiplayer.
413 * 123 8/03/99 6:21p Jefff
416 * 122 8/03/99 3:44p Andsager
417 * Launch laucher if trying to run FS without first having configured
420 * 121 8/03/99 12:45p Dave
423 * 120 8/02/99 9:13p Dave
426 * 119 7/30/99 10:31p Dave
427 * Added comm menu to the configurable hud files.
429 * 118 7/30/99 5:17p Andsager
430 * first fs2demo checksums
432 * 117 7/29/99 3:09p Anoop
434 * 116 7/29/99 12:05a Dave
435 * Nebula speed optimizations.
437 * 115 7/27/99 8:59a Andsager
438 * Make major, minor version consistent for all builds. Only show major
439 * and minor for launcher update window.
441 * 114 7/26/99 5:50p Dave
442 * Revised ingame join. Better? We'll see....
444 * 113 7/26/99 5:27p Andsager
445 * Add training mission as builtin to demo build
447 * 112 7/24/99 1:54p Dave
448 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
451 * 111 7/22/99 4:00p Dave
452 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
454 * 110 7/21/99 8:10p Dave
455 * First run of supernova effect.
457 * 109 7/20/99 1:49p Dave
458 * Peter Drake build. Fixed some release build warnings.
460 * 108 7/19/99 2:26p Andsager
461 * set demo multiplayer missions
463 * 107 7/18/99 5:19p Dave
464 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
466 * 106 7/16/99 1:50p Dave
467 * 8 bit aabitmaps. yay.
469 * 105 7/15/99 3:07p Dave
470 * 32 bit detection support. Mouse coord commandline.
472 * 104 7/15/99 2:13p Dave
473 * Added 32 bit detection.
475 * 103 7/15/99 9:20a Andsager
476 * FS2_DEMO initial checkin
478 * 102 7/14/99 11:02a Dave
479 * Skill level default back to easy. Blech.
481 * 101 7/09/99 5:54p Dave
482 * Seperated cruiser types into individual types. Added tons of new
483 * briefing icons. Campaign screen.
485 * 100 7/08/99 4:43p Andsager
486 * New check for sparky_hi and print if not found.
488 * 99 7/08/99 10:53a Dave
489 * New multiplayer interpolation scheme. Not 100% done yet, but still
490 * better than the old way.
492 * 98 7/06/99 4:24p Dave
493 * Mid-level checkin. Starting on some potentially cool multiplayer
496 * 97 7/06/99 3:35p Andsager
497 * Allow movie to play before red alert mission.
499 * 96 7/03/99 5:50p Dave
500 * Make rotated bitmaps draw properly in padlock views.
502 * 95 7/02/99 9:55p Dave
503 * Player engine wash sound.
505 * 94 7/02/99 4:30p Dave
506 * Much more sophisticated lightning support.
508 * 93 6/29/99 7:52p Dave
509 * Put in exception handling in FS2.
511 * 92 6/22/99 9:37p Dave
512 * Put in pof spewing.
514 * 91 6/16/99 4:06p Dave
515 * New pilot info popup. Added new draw-bitmap-as-poly function.
517 * 90 6/15/99 1:56p Andsager
518 * For release builds, allow start up in high res only with
521 * 89 6/15/99 9:34a Dave
522 * Fixed key checking in single threaded version of the stamp notification
525 * 88 6/09/99 2:55p Andsager
526 * Allow multiple asteroid subtypes (of large, medium, small) and follow
529 * 87 6/08/99 1:14a Dave
530 * Multi colored hud test.
532 * 86 6/04/99 9:52a Dave
533 * Fixed some rendering problems.
535 * 85 6/03/99 10:15p Dave
536 * Put in temporary main hall screen.
538 * 84 6/02/99 6:18p Dave
539 * Fixed TNT lockup problems! Wheeeee!
541 * 83 6/01/99 3:52p Dave
542 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
543 * dead popup, pxo find player popup, pxo private room popup.
545 * 82 5/26/99 1:28p Jasenw
546 * changed coords for loading ani
548 * 81 5/26/99 11:46a Dave
549 * Added ship-blasting lighting and made the randomization of lighting
550 * much more customizable.
552 * 80 5/24/99 5:45p Dave
553 * Added detail levels to the nebula, with a decent speedup. Split nebula
554 * lightning into its own section.
564 #include "systemvars.h"
569 #include "starfield.h"
570 #include "lighting.h"
575 #include "fireballs.h"
579 #include "floating.h"
580 #include "gamesequence.h"
582 #include "optionsmenu.h"
583 #include "playermenu.h"
584 #include "trainingmenu.h"
585 #include "techmenu.h"
588 #include "hudmessage.h"
590 #include "missiongoals.h"
591 #include "missionparse.h"
596 #include "multiutil.h"
597 #include "multimsgs.h"
599 #include "multi_pxo.h"
602 #include "freespace.h"
603 #include "managepilot.h"
605 #include "contexthelp.h"
608 #include "missionbrief.h"
609 #include "missiondebrief.h"
611 #include "missionshipchoice.h"
613 #include "hudconfig.h"
614 #include "controlsconfig.h"
615 #include "missionmessage.h"
616 #include "missiontraining.h"
618 #include "hudtarget.h"
620 #include "eventmusic.h"
621 #include "animplay.h"
622 #include "missionweaponchoice.h"
623 #include "missionlog.h"
624 #include "audiostr.h"
626 #include "missioncampaign.h"
628 #include "missionhotkey.h"
629 #include "objectsnd.h"
630 #include "cmeasure.h"
632 #include "linklist.h"
633 #include "shockwave.h"
634 #include "afterburner.h"
639 #include "stand_server.h"
640 #include "pcxutils.h"
641 #include "hudtargetbox.h"
642 #include "multi_xfer.h"
643 #include "hudescort.h"
644 #include "multiutil.h"
647 #include "multiteamselect.h"
649 #include "readyroom.h"
650 #include "mainhallmenu.h"
651 #include "multilag.h"
653 #include "particle.h"
655 #include "multi_ingame.h"
656 #include "snazzyui.h"
657 #include "asteroid.h"
658 #include "popupdead.h"
659 #include "multi_voice.h"
660 #include "missioncmdbrief.h"
661 #include "redalert.h"
662 #include "gameplayhelp.h"
663 #include "multilag.h"
664 #include "staticrand.h"
665 #include "multi_pmsg.h"
666 #include "levelpaging.h"
667 #include "observer.h"
668 #include "multi_pause.h"
669 #include "multi_endgame.h"
670 #include "cutscenes.h"
671 #include "multi_respawn.h"
673 #include "multi_obj.h"
674 #include "multi_log.h"
676 #include "localize.h"
677 #include "osregistry.h"
678 #include "barracks.h"
679 #include "missionpause.h"
681 #include "alphacolors.h"
682 #include "objcollide.h"
685 #include "neblightning.h"
686 #include "shipcontrails.h"
689 #include "multi_dogfight.h"
690 #include "multi_rate.h"
691 #include "muzzleflash.h"
695 #include "mainhalltemp.h"
696 #include "exceptionhandler.h"
697 #include "supernova.h"
698 #include "hudshield.h"
699 // #include "names.h"
701 #include "missionloopbrief.h"
705 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
711 // 1.00.04 5/26/98 MWA -- going final (12 pm)
712 // 1.00.03 5/26/98 MWA -- going final (3 am)
713 // 1.00.02 5/25/98 MWA -- going final
714 // 1.00.01 5/25/98 MWA -- going final
715 // 0.90 5/21/98 MWA -- getting ready for final.
716 // 0.10 4/9/98. Set by MK.
718 // Demo version: (obsolete since DEMO codebase split from tree)
719 // 0.03 4/10/98 AL. Interplay rev
720 // 0.02 4/8/98 MK. Increased when this system was modified.
721 // 0.01 4/7/98? AL. First release to Interplay QA.
724 // 1.00 5/28/98 AL. First release to Interplay QA.
726 void game_level_init(int seed = -1);
727 void game_post_level_init();
728 void game_do_frame();
729 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
730 void game_reset_time();
731 void game_show_framerate(); // draws framerate in lower right corner
733 void Do_model_timings_test();
735 int Game_no_clear = 0;
737 int Pofview_running = 0;
738 int Nebedit_running = 0;
739 int Fonttool_running = 0;
741 typedef struct big_expl_flash {
742 float max_flash_intensity; // max intensity
743 float cur_flash_intensity; // cur intensity
744 int flash_start; // start time
747 #define FRAME_FILTER 16
749 #define DEFAULT_SKILL_LEVEL 1
750 int Game_skill_level = DEFAULT_SKILL_LEVEL;
752 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
753 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
755 #define EXE_FNAME ("fs2.exe")
756 #define LAUNCHER_FNAME ("freespace2.exe")
759 // JAS: Code for warphole camera.
760 // Needs to be cleaned up.
761 vector Camera_pos = ZERO_VECTOR;
762 vector Camera_velocity = ZERO_VECTOR;
763 vector Camera_desired_velocity = ZERO_VECTOR;
764 matrix Camera_orient = IDENTITY_MATRIX;
765 float Camera_damping = 1.0f;
766 float Camera_time = 0.0f;
767 float Warpout_time = 0.0f;
768 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
769 int Warpout_sound = -1;
771 int Use_joy_mouse = 0;
772 int Use_palette_flash = 1;
773 int Show_area_effect = 0;
774 object *Last_view_target = NULL;
776 int dogfight_blown = 0;
779 float frametimes[FRAME_FILTER];
780 float frametotal = 0.0f;
784 int Show_framerate = 0;
786 int Show_framerate = 1;
789 int Framerate_cap = 120;
792 int Show_target_debug_info = 0;
793 int Show_target_weapons = 0;
797 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
800 int Debug_octant = -1;
802 fix Game_time_compression = F1_0;
804 // if the ships.tbl the player has is valid
805 int Game_ships_tbl_valid = 0;
807 // if the weapons.tbl the player has is valid
808 int Game_weapons_tbl_valid = 0;
812 extern int Player_attacking_enabled;
816 int Pre_player_entry;
818 int Fred_running = 0;
819 char Game_current_mission_filename[MAX_FILENAME_LEN];
820 int game_single_step = 0;
821 int last_single_step=0;
823 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
824 extern int MSG_WINDOW_Y_START;
825 extern int MSG_WINDOW_HEIGHT;
827 int game_zbuffer = 1;
828 //static int Game_music_paused;
829 static int Game_paused;
833 #define EXPIRE_BAD_CHECKSUM 1
834 #define EXPIRE_BAD_TIME 2
836 extern void ssm_init();
837 extern void ssm_level_init();
838 extern void ssm_process();
840 extern button_info Multi_ship_status_bi;
842 // static variable to contain the time this version was built
843 // commented out for now until
844 // I figure out how to get the username into the file
845 //static char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
847 // defines and variables used for dumping frame for making trailers.
849 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
850 int Debug_dump_trigger = 0;
851 int Debug_dump_frame_count;
852 int Debug_dump_frame_num = 0;
853 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
856 // amount of time to wait after the player has died before we display the death died popup
857 #define PLAYER_DIED_POPUP_WAIT 2500
858 int Player_died_popup_wait = -1;
859 time_t Player_multi_died_check = -1;
861 // builtin mission list stuff
863 int Game_builtin_mission_count = 6;
864 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
865 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
866 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
867 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
868 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
869 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
870 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
872 #elif defined(FS1_DEMO)
873 int Game_builtin_mission_count = 5;
874 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
875 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
876 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
877 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
878 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
879 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
881 #elif defined(PD_BUILD)
882 int Game_builtin_mission_count = 4;
883 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
884 { "sm1-01.fs2", (FSB_FROM_VOLITION) },
885 { "sm1-05.fs2", (FSB_FROM_VOLITION) },
886 { "sm1-01", (FSB_FROM_VOLITION) },
887 { "sm1-05", (FSB_FROM_VOLITION) },
889 #elif defined(MULTIPLAYER_BETA)
890 int Game_builtin_mission_count = 17;
891 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
893 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
894 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
895 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
896 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
897 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
898 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
899 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
900 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
901 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
902 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
903 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
904 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
905 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
906 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
907 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
908 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
909 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
911 #elif defined(OEM_BUILD)
912 int Game_builtin_mission_count = 17;
913 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
914 // oem version - act 1 only
915 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
918 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
919 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
920 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
921 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
922 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
923 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
924 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
925 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
926 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
927 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
928 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
929 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
930 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
931 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
932 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
933 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) }
935 #elif defined(MAKE_FS1)
936 int Game_builtin_mission_count = 125;
937 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
938 // single player campaign
939 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
942 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
943 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
944 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
945 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
946 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
947 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
948 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
949 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
950 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
951 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
954 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
955 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
956 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
957 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
958 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
959 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
960 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
961 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
962 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
963 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
966 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
967 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
968 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
969 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
970 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
971 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
972 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
973 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
974 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
977 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
978 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
979 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
982 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
983 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
984 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
985 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
986 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
989 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
990 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
992 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
993 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
994 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
995 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
996 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
997 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
998 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
999 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1000 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1001 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1002 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1003 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1004 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1005 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1006 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1007 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1008 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1009 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1010 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1012 // SilentThreat missions
1013 // Main SilentThreat campaign
1014 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE) },
1016 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1017 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1018 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1019 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1020 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1021 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1022 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1023 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1024 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1025 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1026 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1027 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1029 // SilentThreat Part 1 - multi-coop
1030 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1032 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1033 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1034 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1036 // SilentThreat Part 2 - multi-coop
1037 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1039 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1040 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1041 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1043 // SilentThreat Part 3 - multi-coop
1044 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1046 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1047 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1048 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1050 // SilentThreat Part 4 - multi-coop
1051 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1053 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1054 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1055 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1057 // multiplayer missions
1058 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1059 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1060 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1061 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1062 // user supplied missions
1063 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1064 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1065 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1066 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1067 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1068 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1069 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1070 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1071 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1072 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1073 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1074 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1075 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1076 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1077 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1078 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1079 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1080 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1081 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1082 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1083 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1084 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1085 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1086 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1087 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1088 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1089 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1090 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1091 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1092 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1093 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1094 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1097 int Game_builtin_mission_count = 92;
1098 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1099 // single player campaign
1100 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
1103 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1104 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1105 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1106 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1107 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1108 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1109 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1110 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1111 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1112 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1113 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1114 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1115 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1116 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1117 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1118 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1119 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1120 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1121 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1124 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1125 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1126 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1127 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1128 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1129 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1130 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1131 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1132 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1133 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1136 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1137 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1138 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1139 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1140 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1141 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1142 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1143 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1144 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1145 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1146 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1147 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1149 // multiplayer missions
1152 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1153 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1154 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1157 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1158 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1159 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1160 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1163 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1164 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1165 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1166 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1167 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1168 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1169 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1170 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1171 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1172 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1173 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1174 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1175 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1176 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1177 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1178 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1179 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1180 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1181 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1182 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1183 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1184 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1185 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1186 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1187 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1188 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1189 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1190 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1193 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1194 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1195 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1196 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1197 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1198 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1199 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1200 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1201 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1202 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1205 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1206 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1207 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1208 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1209 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1214 // Internal function prototypes
1215 void game_maybe_draw_mouse(float frametime);
1216 void init_animating_pointer();
1217 void load_animating_pointer(const char *filename, int dx, int dy);
1218 void unload_animating_pointer();
1219 void game_do_training_checks();
1220 void game_shutdown(void);
1221 void game_show_event_debug(float frametime);
1222 void game_event_debug_init();
1224 void demo_upsell_init(int end_of_demo);
1225 void demo_upsell_do();
1226 void demo_upsell_close();
1227 void game_start_subspace_ambient_sound();
1228 void game_stop_subspace_ambient_sound();
1229 void verify_ships_tbl();
1230 void verify_weapons_tbl();
1231 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1232 extern "C" void display_title_screen();
1235 // loading background filenames
1236 static const char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1237 "LoadingBG", // GR_640
1238 "2_LoadingBG" // GR_1024
1242 static const char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1243 "Loading.ani", // GR_640
1244 "2_Loading.ani" // GR_1024
1247 #if defined(FS2_DEMO)
1248 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1252 #elif defined(OEM_BUILD)
1253 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1262 // How much RAM is on this machine. Set in WinMain
1263 static int Freespace_total_ram = 0;
1266 float Game_flash_red = 0.0f;
1267 float Game_flash_green = 0.0f;
1268 float Game_flash_blue = 0.0f;
1269 float Sun_spot = 0.0f;
1270 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1272 // game shudder stuff (in ms)
1273 int Game_shudder_time = -1;
1274 int Game_shudder_total = 0;
1275 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1278 sound_env Game_sound_env;
1279 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1280 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1282 int Game_sound_env_update_timestamp;
1284 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1287 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1289 fs_builtin_mission *game_find_builtin_mission(const char *filename)
1293 // look through all existing builtin missions
1294 for(idx=0; idx<Game_builtin_mission_count; idx++){
1295 if(!SDL_strcasecmp(Game_builtin_mission_list[idx].filename, filename)){
1296 return &Game_builtin_mission_list[idx];
1304 int game_get_default_skill_level()
1306 return DEFAULT_SKILL_LEVEL;
1310 void game_flash_reset()
1312 Game_flash_red = 0.0f;
1313 Game_flash_green = 0.0f;
1314 Game_flash_blue = 0.0f;
1316 Big_expl_flash.max_flash_intensity = 0.0f;
1317 Big_expl_flash.cur_flash_intensity = 0.0f;
1318 Big_expl_flash.flash_start = 0;
1321 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1322 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1324 void game_framerate_check_init()
1326 // zero critical time
1327 Gf_critical_time = 0.0f;
1330 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1331 Gf_critical = 15.0f;
1333 Gf_critical = 25.0f;
1337 extern float Framerate;
1338 void game_framerate_check()
1342 // if the current framerate is above the critical level, add frametime
1343 if(Framerate >= Gf_critical){
1344 Gf_critical_time += flFrametime;
1347 if(!Show_framerate){
1351 // display if we're above the critical framerate
1352 if(Framerate < Gf_critical){
1353 gr_set_color_fast(&Color_bright_red);
1354 gr_string(200, y_start, "Framerate warning");
1359 // display our current pct of good frametime
1360 if(f2fl(Missiontime) >= 0.0f){
1361 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1364 gr_set_color_fast(&Color_bright_green);
1366 gr_set_color_fast(&Color_bright_red);
1369 gr_printf(200, y_start, "%d%%", (int)pct);
1374 // Adds a flash effect. These can be positive or negative.
1375 // The range will get capped at around -1 to 1, so stick
1376 // with a range like that.
1377 void game_flash( float r, float g, float b )
1379 Game_flash_red += r;
1380 Game_flash_green += g;
1381 Game_flash_blue += b;
1383 if ( Game_flash_red < -1.0f ) {
1384 Game_flash_red = -1.0f;
1385 } else if ( Game_flash_red > 1.0f ) {
1386 Game_flash_red = 1.0f;
1389 if ( Game_flash_green < -1.0f ) {
1390 Game_flash_green = -1.0f;
1391 } else if ( Game_flash_green > 1.0f ) {
1392 Game_flash_green = 1.0f;
1395 if ( Game_flash_blue < -1.0f ) {
1396 Game_flash_blue = -1.0f;
1397 } else if ( Game_flash_blue > 1.0f ) {
1398 Game_flash_blue = 1.0f;
1403 // Adds a flash for Big Ship explosions
1404 // cap range from 0 to 1
1405 void big_explosion_flash(float flash)
1407 Big_expl_flash.flash_start = timestamp(1);
1411 } else if (flash < 0.0f) {
1415 Big_expl_flash.max_flash_intensity = flash;
1416 Big_expl_flash.cur_flash_intensity = 0.0f;
1419 // Amount to diminish palette towards normal, per second.
1420 #define DIMINISH_RATE 0.75f
1421 #define SUN_DIMINISH_RATE 6.00f
1425 float sn_glare_scale = 1.7f;
1428 dc_get_arg(ARG_FLOAT);
1429 sn_glare_scale = Dc_arg_float;
1432 float Supernova_last_glare = 0.0f;
1433 void game_sunspot_process(float frametime)
1437 float Sun_spot_goal = 0.0f;
1440 sn_stage = supernova_active();
1442 // sunspot differently based on supernova stage
1444 // approaching. player still in control
1447 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1450 light_get_global_dir(&light_dir, 0);
1452 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1455 // scale it some more
1456 dot = dot * (0.5f + (pct * 0.5f));
1459 Sun_spot_goal += (dot * sn_glare_scale);
1462 // draw the sun glow
1463 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1464 // draw the glow for this sun
1465 stars_draw_sun_glow(0);
1468 Supernova_last_glare = Sun_spot_goal;
1471 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1474 Sun_spot_goal = 0.9f;
1475 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1477 if(Sun_spot_goal > 1.0f){
1478 Sun_spot_goal = 1.0f;
1481 Sun_spot_goal *= sn_glare_scale;
1482 Supernova_last_glare = Sun_spot_goal;
1485 // fade to white. display dead popup
1488 Supernova_last_glare += (2.0f * flFrametime);
1489 if(Supernova_last_glare > 2.0f){
1490 Supernova_last_glare = 2.0f;
1493 Sun_spot_goal = Supernova_last_glare;
1500 // check sunspots for all suns
1501 n_lights = light_get_global_count();
1504 for(idx=0; idx<n_lights; idx++){
1505 //(vector *eye_pos, matrix *eye_orient)
1506 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1509 light_get_global_dir(&light_dir, idx);
1511 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1513 Sun_spot_goal += (float)pow(dot,85.0f);
1515 // draw the glow for this sun
1516 stars_draw_sun_glow(idx);
1518 Sun_spot_goal = 0.0f;
1524 Sun_spot_goal = 0.0f;
1528 float dec_amount = frametime*SUN_DIMINISH_RATE;
1530 if ( Sun_spot < Sun_spot_goal ) {
1531 Sun_spot += dec_amount;
1532 if ( Sun_spot > Sun_spot_goal ) {
1533 Sun_spot = Sun_spot_goal;
1535 } else if ( Sun_spot > Sun_spot_goal ) {
1536 Sun_spot -= dec_amount;
1537 if ( Sun_spot < Sun_spot_goal ) {
1538 Sun_spot = Sun_spot_goal;
1544 // Call once a frame to diminish the
1545 // flash effect to 0.
1546 void game_flash_diminish(float frametime)
1548 float dec_amount = frametime*DIMINISH_RATE;
1550 if ( Game_flash_red > 0.0f ) {
1551 Game_flash_red -= dec_amount;
1552 if ( Game_flash_red < 0.0f )
1553 Game_flash_red = 0.0f;
1555 Game_flash_red += dec_amount;
1556 if ( Game_flash_red > 0.0f )
1557 Game_flash_red = 0.0f;
1560 if ( Game_flash_green > 0.0f ) {
1561 Game_flash_green -= dec_amount;
1562 if ( Game_flash_green < 0.0f )
1563 Game_flash_green = 0.0f;
1565 Game_flash_green += dec_amount;
1566 if ( Game_flash_green > 0.0f )
1567 Game_flash_green = 0.0f;
1570 if ( Game_flash_blue > 0.0f ) {
1571 Game_flash_blue -= dec_amount;
1572 if ( Game_flash_blue < 0.0f )
1573 Game_flash_blue = 0.0f;
1575 Game_flash_blue += dec_amount;
1576 if ( Game_flash_blue > 0.0f )
1577 Game_flash_blue = 0.0f;
1580 // update big_explosion_cur_flash
1581 #define TIME_UP 1500
1582 #define TIME_DOWN 2500
1583 int duration = TIME_UP + TIME_DOWN;
1584 int time = timestamp_until(Big_expl_flash.flash_start);
1585 if (time > -duration) {
1587 if (time < TIME_UP) {
1588 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1591 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1595 if ( Use_palette_flash ) {
1597 // static int or=0, og=0, ob=0;
1599 // Change the 200 to change the color range of colors.
1600 r = fl2i( Game_flash_red*128.0f );
1601 g = fl2i( Game_flash_green*128.0f );
1602 b = fl2i( Game_flash_blue*128.0f );
1604 if ( Sun_spot > 0.0f ) {
1605 r += fl2i(Sun_spot*128.0f);
1606 g += fl2i(Sun_spot*128.0f);
1607 b += fl2i(Sun_spot*128.0f);
1610 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1611 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1612 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1613 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1616 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1617 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1618 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1620 if ( (r!=0) || (g!=0) || (b!=0) ) {
1621 gr_flash( r, g, b );
1623 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1634 void game_level_close()
1636 // De-Initialize the game subsystems
1637 event_music_level_close();
1638 game_stop_looped_sounds();
1640 obj_snd_level_close(); // uninit object-linked persistant sounds
1641 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1642 anim_level_close(); // stop and clean up any anim instances
1643 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1644 shockwave_level_close();
1645 fireball_level_close();
1647 mission_event_shutdown();
1648 asteroid_level_close();
1649 flak_level_close(); // unload flak stuff
1650 neb2_level_close(); // shutdown gaseous nebula stuff
1653 mflash_level_close();
1654 mission_brief_common_reset(); // close out parsed briefing/mission stuff
1656 audiostream_unpause_all();
1661 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1662 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1663 void game_level_init(int seed)
1665 // seed the random number generator
1667 // if no seed was passed, seed the generator either from the time value, or from the
1668 // netgame security flags -- ensures that all players in multiplayer game will have the
1669 // same randon number sequence (with static rand functions)
1670 if ( Game_mode & GM_NORMAL ) {
1671 Game_level_seed = (int)time(NULL);
1673 Game_level_seed = Netgame.security;
1676 // mwa 9/17/98 -- maybe this assert isn't needed????
1677 SDL_assert( !(Game_mode & GM_MULTIPLAYER) );
1678 Game_level_seed = seed;
1680 srand( Game_level_seed );
1682 // semirand function needs to get re-initted every time in multiplayer
1683 if ( Game_mode & GM_MULTIPLAYER ){
1689 Key_normal_game = (Game_mode & GM_NORMAL);
1692 Game_shudder_time = -1;
1694 // Initialize the game subsystems
1695 // timestamp_reset(); // Must be inited before everything else
1697 game_reset_time(); // resets time, and resets saved time too
1699 obj_init(); // Must be inited before the other systems
1700 model_free_all(); // Free all existing models
1701 mission_brief_common_init(); // Free all existing briefing/debriefing text
1702 weapon_level_init();
1703 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1705 player_level_init();
1706 shipfx_flash_init(); // Init the ship gun flash system.
1707 game_flash_reset(); // Reset the flash effect
1708 particle_init(); // Reset the particle system
1712 shield_hit_init(); // Initialize system for showing shield hits
1713 radar_mission_init();
1714 mission_init_goals();
1717 obj_snd_level_init(); // init object-linked persistant sounds
1719 shockwave_level_init();
1720 afterburner_level_init();
1721 scoring_level_init( &Player->stats );
1723 asteroid_level_init();
1724 control_config_clear_used_status();
1725 collide_ship_ship_sounds_init();
1727 Pre_player_entry = 1; // Means the player has not yet entered.
1728 Entry_delay_time = 0; // Could get overwritten in mission read.
1729 fireball_preload(); // page in warphole bitmaps
1731 flak_level_init(); // initialize flak - bitmaps, etc
1732 ct_level_init(); // initialize ships contrails, etc
1733 awacs_level_init(); // initialize AWACS
1734 beam_level_init(); // initialize beam weapons
1735 mflash_level_init();
1737 supernova_level_init();
1739 // multiplayer dogfight hack
1742 shipfx_engine_wash_level_init();
1746 Last_view_target = NULL;
1751 // campaign wasn't ended
1752 Campaign_ended_in_mission = 0;
1755 // called when a mission is over -- does server specific stuff.
1756 void freespace_stop_mission()
1759 Game_mode &= ~GM_IN_MISSION;
1762 // called at frame interval to process networking stuff
1763 void game_do_networking()
1765 SDL_assert( Net_player != NULL );
1766 if (!(Game_mode & GM_MULTIPLAYER)){
1770 // see if this player should be reading/writing data. Bit is set when at join
1771 // screen onward until quits back to main menu.
1772 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1776 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1779 multi_pause_do_frame();
1784 // Loads the best palette for this level, based
1785 // on nebula color and hud color. You could just call palette_load_table with
1786 // the appropriate filename, but who wants to do that.
1787 void game_load_palette()
1789 char palette_filename[1024];
1791 // We only use 3 hud colors right now
1793 SDL_assert( HUD_config.main_color >= 0 );
1794 SDL_assert( HUD_config.main_color <= 2 );
1797 SDL_assert( Mission_palette >= 0 );
1798 SDL_assert( Mission_palette <= 98 );
1801 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1802 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), SDL_arraysize(palette_filename) );
1804 SDL_snprintf( palette_filename, SDL_arraysize(palette_filename), NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1807 mprintf(( "Loading palette %s\n", palette_filename ));
1809 palette_load_table(palette_filename);
1811 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), SDL_arraysize(palette_filename) );
1813 mprintf(( "Loading palette %s\n", palette_filename ));
1817 void game_post_level_init()
1819 // Stuff which gets called after mission is loaded. Because player isn't created until
1820 // after mission loads, some things must get initted after the level loads
1822 model_level_post_init();
1825 hud_setup_escort_list();
1826 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1832 game_event_debug_init();
1835 training_mission_init();
1836 asteroid_create_all();
1838 game_framerate_check_init();
1842 // An estimate as to how high the count passed to game_loading_callback will go.
1843 // This is just a guess, it seems to always be about the same. The count is
1844 // proportional to the code being executed, not the time, so this works good
1845 // for a bar, assuming the code does about the same thing each time you
1846 // load a level. You can find this value by looking at the return value
1847 // of game_busy_callback(NULL), which I conveniently print out to the
1848 // debug output window with the '=== ENDING LOAD ==' stuff.
1849 //#define COUNT_ESTIMATE 3706
1850 #define COUNT_ESTIMATE 1111
1852 int Game_loading_callback_inited = 0;
1854 int Game_loading_background = -1;
1855 anim * Game_loading_ani = NULL;
1856 anim_instance *Game_loading_ani_instance;
1857 int Game_loading_frame=-1;
1858 int Game_loading_ani_bitmap = -1;
1860 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1862 #if defined(FS1_DEMO)
1864 #elif defined(MAKE_FS1)
1875 // This gets called 10x per second and count is the number of times
1876 // game_busy() has been called since the current callback function
1879 void game_loading_callback(int count)
1881 game_do_networking();
1883 SDL_assert( Game_loading_callback_inited==1 );
1884 SDL_assert( Game_loading_ani != NULL );
1886 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1887 if ( framenum > Game_loading_ani->total_frames-1 ) {
1888 framenum = Game_loading_ani->total_frames-1;
1889 } else if ( framenum < 0 ) {
1894 while ( Game_loading_frame < framenum ) {
1895 Game_loading_frame++;
1896 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1900 if (Game_loading_ani_bitmap > -1) {
1901 bm_release(Game_loading_ani_bitmap);
1904 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1905 Game_loading_ani_bitmap = cbitmap;
1908 if (Game_loading_background > -1) {
1909 gr_set_bitmap(Game_loading_background, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1915 if (Game_loading_ani_bitmap > -1) {
1916 gr_set_bitmap(Game_loading_ani_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1917 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0], Game_loading_ani_coords[gr_screen.res][1]);
1922 #ifdef __EMSCRIPTEN__
1923 //emscripten_sleep(10);
1927 void game_loading_callback_init()
1929 SDL_assert( Game_loading_callback_inited==0 );
1931 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1933 common_set_interface_palette("InterfacePalette"); // set the interface palette
1937 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1938 SDL_assert( Game_loading_ani != NULL );
1939 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1940 SDL_assert( Game_loading_ani_instance != NULL );
1941 Game_loading_frame = -1;
1942 Game_loading_ani_bitmap = -1;
1944 Game_loading_callback_inited = 1;
1946 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1952 void game_loading_callback_close()
1954 SDL_assert( Game_loading_callback_inited==1 );
1956 // Make sure bar shows all the way over.
1957 game_loading_callback(COUNT_ESTIMATE);
1960 int real_count = game_busy_callback( NULL );
1962 mprintf(( "=================== ENDING LOAD ================\n" ));
1963 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1964 mprintf(( "================================================\n" ));
1966 game_busy_callback( NULL );
1971 Game_loading_callback_inited = 0;
1973 free_anim_instance(Game_loading_ani_instance);
1974 Game_loading_ani_instance = NULL;
1975 anim_free(Game_loading_ani);
1976 Game_loading_ani = NULL;
1978 if (Game_loading_ani_bitmap > -1) {
1979 bm_release(Game_loading_ani_bitmap);
1980 Game_loading_ani_bitmap = -1;
1983 if (Game_loading_background > -1) {
1984 bm_release(Game_loading_background);
1985 Game_loading_background = -1;
1988 common_free_interface_palette(); // restore game palette
1991 gr_set_font( FONT1 );
1994 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1996 void game_maybe_update_sound_environment()
1998 // do nothing for now
2001 // Assign the sound environment for the game, based on the current mission
2003 void game_assign_sound_environment()
2006 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
2007 Game_sound_env.id = SND_ENV_DRUGGED;
2008 Game_sound_env.volume = 0.800f;
2009 Game_sound_env.damping = 1.188f;
2010 Game_sound_env.decay = 6.392f;
2012 } else if (Num_asteroids > 30) {
2013 Game_sound_env.id = SND_ENV_AUDITORIUM;
2014 Game_sound_env.volume = 0.603f;
2015 Game_sound_env.damping = 0.5f;
2016 Game_sound_env.decay = 4.279f;
2019 Game_sound_env = Game_default_sound_env;
2022 Game_sound_env = Game_default_sound_env;
2025 Game_sound_env_update_timestamp = timestamp(1);
2028 // function which gets called before actually entering the mission. It is broken down into a funciton
2029 // since it will get called in one place from a single player game and from another place for
2030 // a multiplayer game
2032 void freespace_mission_load_stuff()
2034 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2035 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2036 if(!(Game_mode & GM_STANDALONE_SERVER)){
2038 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2040 game_loading_callback_init();
2042 event_music_level_init(); // preloads the first 2 seconds for each event music track
2045 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2048 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2051 ship_assign_sound_all(); // assign engine sounds to ships
2052 game_assign_sound_environment(); // assign the sound environment for this mission
2055 // call function in missionparse.cpp to fixup player/ai stuff.
2056 mission_parse_fixup_players();
2059 // Load in all the bitmaps for this level
2064 game_loading_callback_close();
2066 // the only thing we need to call on the standalone for now.
2068 // call function in missionparse.cpp to fixup player/ai stuff.
2069 mission_parse_fixup_players();
2071 // Load in all the bitmaps for this level
2076 time_t load_gl_init;
2077 time_t load_mission_load;
2078 time_t load_post_level_init;
2079 time_t load_mission_stuff;
2081 // tells the server to load the mission and initialize structures
2083 int game_start_mission()
2085 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2087 load_gl_init = time(NULL);
2089 load_gl_init = time(NULL) - load_gl_init;
2091 if (Game_mode & GM_MULTIPLAYER) {
2092 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2094 // clear multiplayer stats
2095 init_multiplayer_stats();
2098 load_mission_load = time(NULL);
2099 if (mission_load()) {
2100 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2101 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2102 gameseq_post_event(GS_EVENT_MAIN_MENU);
2104 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2109 load_mission_load = time(NULL) - load_mission_load;
2111 // If this is a red alert mission in campaign mode, bash wingman status
2112 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2113 red_alert_bash_wingman_status();
2116 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2117 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2118 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2120 game_load_palette();
2124 load_post_level_init = time(NULL);
2125 game_post_level_init();
2126 load_post_level_init = time(NULL) - load_post_level_init;
2130 Do_model_timings_test();
2134 load_mission_stuff = time(NULL);
2135 freespace_mission_load_stuff();
2136 load_mission_stuff = time(NULL) - load_mission_stuff;
2141 int Interface_framerate = 0;
2144 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2145 DCF_BOOL( show_framerate, Show_framerate )
2146 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2147 DCF_BOOL( show_target_weapons, Show_target_weapons )
2148 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2149 DCF_BOOL( sound, Sound_enabled )
2150 DCF_BOOL( zbuffer, game_zbuffer )
2151 DCF_BOOL( shield_system, New_shield_system )
2152 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2153 DCF_BOOL( player_attacking, Player_attacking_enabled )
2154 DCF_BOOL( show_waypoints, Show_waypoints )
2155 DCF_BOOL( show_area_effect, Show_area_effect )
2156 DCF_BOOL( show_net_stats, Show_net_stats )
2157 DCF_BOOL( log, Log_debug_output_to_file )
2158 DCF_BOOL( training_msg_method, Training_msg_method )
2159 DCF_BOOL( show_player_pos, Show_player_pos )
2160 DCF_BOOL(i_framerate, Interface_framerate )
2162 DCF(show_mem,"Toggles showing mem usage")
2165 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2166 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2167 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2168 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2174 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2176 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2177 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2181 DCF(show_cpu,"Toggles showing cpu usage")
2184 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2185 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2186 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2187 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2193 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2195 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2196 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2203 // AL 4-8-98: always allow players to display their framerate
2206 DCF_BOOL( show_framerate, Show_framerate )
2213 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2216 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2217 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2218 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2219 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2221 if ( Dc_help ) dc_printf( "Usage: use_joy_mouse [bool]\nSets use_joy_mouse to true or false. If nothing passed, then toggles it.\n" );
2222 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2224 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2227 DCF(palette_flash,"Toggles palette flash effect on/off")
2230 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2231 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2232 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2233 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2235 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2236 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2239 int Use_low_mem = 0;
2241 DCF(low_mem,"Uses low memory settings regardless of RAM")
2244 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2245 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2246 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2247 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2249 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2250 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2252 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2256 int Framerate_delay = 0;
2258 float Freespace_gamma = 1.8f;
2260 DCF(gamma,"Sets Gamma factor")
2263 dc_get_arg(ARG_FLOAT|ARG_NONE);
2264 if ( Dc_arg_type & ARG_FLOAT ) {
2265 Freespace_gamma = Dc_arg_float;
2267 dc_printf( "Gamma reset to 1.0f\n" );
2268 Freespace_gamma = 1.0f;
2270 if ( Freespace_gamma < 0.1f ) {
2271 Freespace_gamma = 0.1f;
2272 } else if ( Freespace_gamma > 5.0f ) {
2273 Freespace_gamma = 5.0f;
2275 gr_set_gamma(Freespace_gamma);
2277 char tmp_gamma_string[32];
2278 SDL_snprintf( tmp_gamma_string, SDL_arraysize(tmp_gamma_string), NOX("%.2f"), Freespace_gamma );
2279 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2283 dc_printf( "Usage: gamma <float>\n" );
2284 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2285 Dc_status = 0; // don't print status if help is printed. Too messy.
2289 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2293 extern void bm_init();
2298 Game_current_mission_filename[0] = 0;
2300 // seed the random number generator
2301 Game_init_seed = (int)time(NULL);
2302 srand( Game_init_seed );
2304 Framerate_delay = 0;
2315 // Initialize the timer before the os
2322 //Initialize the libraries
2323 s1 = timer_get_milliseconds();
2326 if ( cfile_init() ) { // initialize before calling any cfopen stuff!!!
2331 e1 = timer_get_milliseconds();
2334 // time a bunch of cfopens
2336 s2 = timer_get_milliseconds();
2338 for(int idx=0; idx<10000; idx++){
2339 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2344 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2346 e2 = timer_get_milliseconds();
2349 os_init( Osreg_class_name, Osreg_app_name );
2350 os_set_title(Osreg_title);
2352 // initialize localization module. Make sure this is down AFTER initialzing OS.
2353 // int t1 = timer_get_milliseconds();
2354 lcl_init( detect_lang() );
2356 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2358 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2361 // verify that he has a valid weapons.tbl
2362 verify_weapons_tbl();
2364 // Output version numbers to registry for auto patching purposes
2365 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2366 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2367 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2369 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2370 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2371 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2373 // show the FPS counter if the config file says so
2374 Show_framerate = os_config_read_uint( "Video", "ShowFPS", Show_framerate );
2376 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2377 Asteroids_enabled = 1;
2380 /////////////////////////////
2382 /////////////////////////////
2384 if (!Is_standalone) {
2388 /////////////////////////////
2390 /////////////////////////////
2397 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2400 display_title_screen();
2404 // If less than 48MB of RAM, use low memory model.
2405 if ( (Freespace_total_ram < 48) || Use_low_mem ) {
2406 mprintf(( "Using normal memory settings...\n" ));
2407 bm_set_low_mem(1); // Use every other frame of bitmaps
2409 mprintf(( "Using high memory settings...\n" ));
2410 bm_set_low_mem(0); // Use all frames of bitmaps
2413 // load non-darkening pixel defs
2414 palman_load_pixels();
2416 // hud shield icon stuff
2417 hud_shield_game_init();
2419 control_config_common_init(); // sets up localization stuff in the control config
2425 gamesnd_parse_soundstbl();
2430 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2435 player_controls_init();
2438 //if(!Is_standalone){
2446 ship_init(); // read in ships.tbl
2448 mission_campaign_init(); // load in the default campaign
2450 // navmap_init(); // init the navigation map system
2451 context_help_init();
2452 techroom_intel_init(); // parse species.tbl, load intel info
2454 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2455 init_animating_pointer();
2457 mission_brief_common_init(); // Mark all the briefing structures as empty.
2458 gr_font_init(); // loads up all fonts
2460 neb2_init(); // fullneb stuff
2464 player_tips_init(); // helpful tips
2467 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2468 pilot_load_pic_list();
2469 pilot_load_squad_pic_list();
2471 load_animating_pointer(NOX("cursor"), 0, 0);
2473 // initialize alpha colors
2474 alpha_colors_init();
2477 // Game_music_paused = 0;
2480 if (Is_standalone) {
2481 std_init_standalone();
2484 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2485 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2487 mprintf(("cfile_init() took %d\n", e1 - s1));
2488 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2491 char transfer_text[128];
2493 float Start_time = 0.0f;
2495 float Framerate = 0.0f;
2497 float Timing_total = 0.0f;
2498 float Timing_render2 = 0.0f;
2499 float Timing_render3 = 0.0f;
2500 float Timing_flip = 0.0f;
2501 float Timing_clear = 0.0f;
2503 MONITOR(NumPolysDrawn);
2509 void game_get_framerate()
2511 char text[128] = "";
2513 if ( frame_int == -1 ) {
2515 for (i=0; i<FRAME_FILTER; i++ ) {
2516 frametimes[i] = 0.0f;
2521 frametotal -= frametimes[frame_int];
2522 frametotal += flFrametime;
2523 frametimes[frame_int] = flFrametime;
2524 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2526 if ( frametotal != 0.0 ) {
2527 if ( Framecount >= FRAME_FILTER )
2528 Framerate = FRAME_FILTER / frametotal;
2530 Framerate = Framecount / frametotal;
2531 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: %.1f"), Framerate );
2533 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: ?") );
2537 if (Show_framerate) {
2538 gr_set_color_fast(&HUD_color_debug);
2539 gr_string( 570, 2, text );
2543 void game_show_framerate()
2547 cur_time = f2fl(timer_get_approx_seconds());
2548 if (cur_time - Start_time > 30.0f) {
2549 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2550 Start_time += 1000.0f;
2553 //mprintf(( "%s\n", text ));
2556 if ( Debug_dump_frames )
2560 // possibly show control checking info
2561 control_check_indicate();
2563 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2564 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2565 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2566 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2569 if ( Show_cpu == 1 ) {
2574 dy = gr_get_font_height() + 1;
2576 gr_set_color_fast(&HUD_color_debug);
2579 extern int Gr_textures_in;
2580 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2583 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2585 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2587 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2589 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2591 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2596 extern int Num_pairs; // Number of object pairs that were checked.
2597 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2600 extern int Num_pairs_checked; // What percent of object pairs were checked.
2601 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2603 Num_pairs_checked = 0;
2607 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2610 if ( Timing_total > 0.01f ) {
2611 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2613 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2615 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2617 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2619 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2628 dy = gr_get_font_height() + 1;
2630 gr_set_color_fast(&HUD_color_debug);
2633 extern int TotalRam;
2634 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2639 extern int Model_ram;
2640 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2644 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2646 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2650 extern int Gr_textures_in;
2651 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2656 if ( Show_player_pos ) {
2660 gr_printf(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));
2663 MONITOR_INC(NumPolys, modelstats_num_polys);
2664 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2665 MONITOR_INC(NumVerts, modelstats_num_verts );
2667 modelstats_num_polys = 0;
2668 modelstats_num_polys_drawn = 0;
2669 modelstats_num_verts = 0;
2670 modelstats_num_sortnorms = 0;
2674 void game_show_standalone_framerate()
2676 float frame_rate=30.0f;
2677 if ( frame_int == -1 ) {
2679 for (i=0; i<FRAME_FILTER; i++ ) {
2680 frametimes[i] = 0.0f;
2685 frametotal -= frametimes[frame_int];
2686 frametotal += flFrametime;
2687 frametimes[frame_int] = flFrametime;
2688 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2690 if ( frametotal != 0.0 ) {
2691 if ( Framecount >= FRAME_FILTER ){
2692 frame_rate = FRAME_FILTER / frametotal;
2694 frame_rate = Framecount / frametotal;
2697 std_set_standalone_fps(frame_rate);
2701 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2702 void game_show_time_left()
2706 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2707 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2708 // checking how much time is left
2710 if ( Mission_end_time == -1 ){
2714 diff = f2i(Mission_end_time - Missiontime);
2715 // be sure to bash to 0. diff could be negative on frame that we quit mission
2720 hud_set_default_color();
2721 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2724 //========================================================================================
2725 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2726 //========================================================================================
2730 DCF(ai_pause,"Pauses ai")
2733 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2734 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2735 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2736 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2739 obj_init_all_ships_physics();
2742 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2743 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2746 DCF(single_step,"Single steps the game")
2749 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2750 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2751 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2752 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2754 last_single_step = 0; // Make so single step waits a frame before stepping
2757 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2758 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2761 DCF_BOOL(physics_pause, physics_paused)
2762 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2763 DCF_BOOL(ai_firing, Ai_firing_enabled )
2765 // Create some simple aliases to these commands...
2766 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2767 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2768 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2769 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2770 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2773 //========================================================================================
2774 //========================================================================================
2777 void game_training_pause_do()
2781 key = game_check_key();
2783 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2790 void game_increase_skill_level()
2793 if (Game_skill_level >= NUM_SKILL_LEVELS){
2794 Game_skill_level = 0;
2798 int Player_died_time;
2800 int View_percent = 100;
2803 DCF(view, "Sets the percent of the 3d view to render.")
2806 dc_get_arg(ARG_INT);
2807 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2808 View_percent = Dc_arg_int;
2810 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2816 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2820 dc_printf("View is set to %d%%\n", View_percent );
2825 // Set the clip region for the 3d rendering window
2826 void game_set_view_clip()
2828 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2829 // Set the clip region for the letterbox "dead view"
2830 int yborder = gr_screen.max_h/4;
2832 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2833 // J.S. I've changed my ways!! See the new "no constants" code!!!
2834 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2836 // Set the clip region for normal view
2837 if ( View_percent >= 100 ) {
2840 int xborder, yborder;
2842 if ( View_percent < 5 ) {
2846 float fp = i2fl(View_percent)/100.0f;
2847 int fi = fl2i(fl_sqrt(fp)*100.0f);
2848 if ( fi > 100 ) fi=100;
2850 xborder = ( gr_screen.max_w*(100-fi) )/200;
2851 yborder = ( gr_screen.max_h*(100-fi) )/200;
2853 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2859 void show_debug_stuff()
2862 int laser_count = 0, missile_count = 0;
2864 for (i=0; i<MAX_OBJECTS; i++) {
2865 if (Objects[i].type == OBJ_WEAPON){
2866 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2868 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2874 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2877 extern int Tool_enabled;
2879 time_t tst_time = 0;
2882 int tst_bitmap = -1;
2884 float tst_offset, tst_offset_total;
2887 void game_tst_frame_pre()
2895 g3_rotate_vertex(&v, &tst_pos);
2896 g3_project_vertex(&v);
2899 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2903 // big ship? always tst
2905 // within 3000 meters
2906 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2910 // within 300 meters
2911 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2918 void game_tst_frame()
2928 tst_time = time(NULL);
2930 // load the tst bitmap
2931 switch((int)frand_range(0.0f, 3.0)){
2933 tst_bitmap = bm_load("ig_jim");
2935 mprintf(("TST 0\n"));
2939 tst_bitmap = bm_load("ig_kan");
2941 mprintf(("TST 1\n"));
2945 tst_bitmap = bm_load("ig_jim");
2947 mprintf(("TST 2\n"));
2951 tst_bitmap = bm_load("ig_kan");
2953 mprintf(("TST 3\n"));
2962 // get the tst bitmap dimensions
2964 bm_get_info(tst_bitmap, &w, &h);
2967 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2969 snd_play(&Snds[SND_VASUDAN_BUP]);
2971 // tst x and direction
2975 tst_offset_total = (float)w;
2976 tst_offset = (float)w;
2978 tst_x = (float)gr_screen.max_w;
2979 tst_offset_total = (float)-w;
2980 tst_offset = (float)w;
2988 float diff = (tst_offset_total / 0.5f) * flFrametime;
2994 tst_offset -= fl_abs(diff);
2995 } else if(tst_mode == 2){
2998 tst_offset -= fl_abs(diff);
3002 gr_set_bitmap(tst_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3003 gr_bitmap((int)tst_x, (int)tst_y);
3006 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3010 // if we passed the switch point
3011 if(tst_offset <= 0.0f){
3016 tst_stamp = timestamp(1000);
3017 tst_offset = fl_abs(tst_offset_total);
3028 void game_tst_mark(object *objp, ship *shipp)
3037 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3040 sip = &Ship_info[shipp->ship_info_index];
3047 tst_pos = objp->pos;
3048 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3054 extern void render_shields();
3056 void player_repair_frame(float frametime)
3058 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3060 for(idx=0;idx<MAX_PLAYERS;idx++){
3063 np = &Net_players[idx];
3065 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != NULL) && (Net_player->player_id != Net_players[idx].player_id) && (Net_players[idx].player != NULL) && (Net_players[idx].player->objnum >= 0) && (Net_players[idx].player->objnum < MAX_OBJECTS)){
3067 // don't rearm/repair if the player is dead or dying/departing
3068 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3069 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3074 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3075 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3081 #define NUM_FRAMES_TEST 300
3082 #define NUM_MIXED_SOUNDS 16
3083 void do_timing_test(float frametime)
3085 static int framecount = 0;
3086 static int test_running = 0;
3087 static float test_time = 0.0f;
3089 static int snds[NUM_MIXED_SOUNDS];
3092 if ( test_running ) {
3094 test_time += frametime;
3095 if ( framecount >= NUM_FRAMES_TEST ) {
3097 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3098 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3103 if ( Test_begin == 1 ) {
3109 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3112 // start looping digital sounds
3113 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3114 snds[i] = snd_play_looping( &Snds[i], 0.0f);
3121 DCF(dcf_fov, "Change the field of view")
3124 dc_get_arg(ARG_FLOAT|ARG_NONE);
3125 if ( Dc_arg_type & ARG_NONE ) {
3126 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3127 dc_printf( "Zoom factor reset\n" );
3129 if ( Dc_arg_type & ARG_FLOAT ) {
3130 if (Dc_arg_float < 0.25f) {
3131 Viewer_zoom = 0.25f;
3132 dc_printf("Zoom factor pinned at 0.25.\n");
3133 } else if (Dc_arg_float > 1.25f) {
3134 Viewer_zoom = 1.25f;
3135 dc_printf("Zoom factor pinned at 1.25.\n");
3137 Viewer_zoom = Dc_arg_float;
3143 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3146 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3150 DCF(framerate_cap, "Sets the framerate cap")
3153 dc_get_arg(ARG_INT);
3154 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3155 Framerate_cap = Dc_arg_int;
3157 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3163 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3164 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3165 dc_printf("[n] must be from 1 to 120.\n");
3169 if ( Framerate_cap )
3170 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3172 dc_printf("There is no framerate cap currently active.\n");
3176 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3177 int Show_viewing_from_self = 0;
3179 void say_view_target()
3181 object *view_target;
3183 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3184 view_target = &Objects[Player_ai->target_objnum];
3186 view_target = Player_obj;
3188 if (Game_mode & GM_DEAD) {
3189 if (Player_ai->target_objnum != -1)
3190 view_target = &Objects[Player_ai->target_objnum];
3193 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3194 if (view_target != Player_obj){
3196 char *view_target_name = NULL;
3197 switch(Objects[Player_ai->target_objnum].type) {
3199 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3202 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3203 Viewer_mode &= ~VM_OTHER_SHIP;
3205 case OBJ_JUMP_NODE: {
3206 char jump_node_name[128];
3207 SDL_strlcpy(jump_node_name, XSTR( "jump node", 184), SDL_arraysize(jump_node_name));
3208 view_target_name = jump_node_name;
3209 Viewer_mode &= ~VM_OTHER_SHIP;
3218 if ( view_target_name ) {
3219 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3220 Show_viewing_from_self = 1;
3223 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3224 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3225 Show_viewing_from_self = 1;
3227 if (Show_viewing_from_self)
3228 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3233 Last_view_target = view_target;
3237 float Game_hit_x = 0.0f;
3238 float Game_hit_y = 0.0f;
3240 // Reset at the beginning of each frame
3241 void game_whack_reset()
3247 // Apply a 2d whack to the player
3248 void game_whack_apply( float x, float y )
3250 // Do some force feedback
3251 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3257 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3260 // call to apply a "shudder"
3261 void game_shudder_apply(int time, float intensity)
3263 Game_shudder_time = timestamp(time);
3264 Game_shudder_total = time;
3265 Game_shudder_intensity = intensity;
3268 #define FF_SCALE 10000
3269 void apply_hud_shake(matrix *eye_orient)
3271 if (Viewer_obj == Player_obj) {
3272 physics_info *pi = &Player_obj->phys_info;
3280 // Make eye shake due to afterburner
3281 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3284 dtime = timestamp_until(pi->afterburner_decay);
3288 tangles.p += 0.07f * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3289 tangles.h += 0.07f * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3292 // Make eye shake due to engine wash
3294 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3297 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX;
3298 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX;
3300 // get the intensity
3301 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3305 vm_vec_rand_vec_quick(&rand_vec);
3308 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3312 // make hud shake due to shuddering
3313 if(Game_shudder_time != -1){
3314 // if the timestamp has elapsed
3315 if(timestamp_elapsed(Game_shudder_time)){
3316 Game_shudder_time = -1;
3318 // otherwise apply some shudder
3322 dtime = timestamp_until(Game_shudder_time);
3326 tangles.p += (Game_shudder_intensity / 200.0f) * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3327 tangles.h += (Game_shudder_intensity / 200.0f) * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3332 vm_angles_2_matrix(&tm, &tangles);
3333 SDL_assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3334 SDL_assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3335 SDL_assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3336 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3341 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3343 // Player's velocity just before he blew up. Used to keep camera target moving.
3344 vector Dead_player_last_vel = { { { 1.0f, 1.0f, 1.0f } } };
3346 // Set eye_pos and eye_orient based on view mode.
3347 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3351 static int last_Viewer_mode = 0;
3352 static int last_Game_mode = 0;
3353 static int last_Viewer_objnum = -1;
3355 // This code is supposed to detect camera "cuts"... like going between
3358 // determine if we need to regenerate the nebula
3359 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3360 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3361 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3362 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3363 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3364 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3365 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3366 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3367 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3370 // regenerate the nebula
3374 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3375 //mprintf(( "************** Camera cut! ************\n" ));
3376 last_Viewer_mode = Viewer_mode;
3377 last_Game_mode = Game_mode;
3379 // Camera moved. Tell stars & debris to not do blurring.
3385 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3386 player_display_packlock_view();
3389 game_set_view_clip();
3391 if (Game_mode & GM_DEAD) {
3392 vector vec_to_deader, view_pos;
3395 Viewer_mode |= VM_DEAD_VIEW;
3397 if (Player_ai->target_objnum != -1) {
3398 int view_from_player = 1;
3400 if (Viewer_mode & VM_OTHER_SHIP) {
3401 // View from target.
3402 Viewer_obj = &Objects[Player_ai->target_objnum];
3404 last_Viewer_objnum = Player_ai->target_objnum;
3406 if ( Viewer_obj->type == OBJ_SHIP ) {
3407 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3408 view_from_player = 0;
3411 last_Viewer_objnum = -1;
3414 if ( view_from_player ) {
3415 // View target from player ship.
3417 *eye_pos = Player_obj->pos;
3418 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3419 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3422 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3424 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3425 dist += flFrametime * 16.0f;
3427 vm_vec_scale(&vec_to_deader, -dist);
3428 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3430 view_pos = Player_obj->pos;
3432 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3433 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3434 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3435 Dead_player_last_vel = Player_obj->phys_info.vel;
3436 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.xyz.x, Player_obj->phys_info.vel.xyz.y, Player_obj->phys_info.vel.xyz.z));
3437 } else if (Player_ai->target_objnum != -1) {
3438 view_pos = Objects[Player_ai->target_objnum].pos;
3440 // Make camera follow explosion, but gradually slow down.
3441 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3442 view_pos = Player_obj->pos;
3443 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3444 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, SDL_min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3447 *eye_pos = Dead_camera_pos;
3449 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3451 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3456 // if supernova shockwave
3457 if(supernova_camera_cut()){
3461 // call it dead view
3462 Viewer_mode |= VM_DEAD_VIEW;
3464 // set eye pos and orient
3465 supernova_set_view(eye_pos, eye_orient);
3467 // If already blown up, these other modes can override.
3468 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3469 Viewer_mode &= ~VM_DEAD_VIEW;
3471 Viewer_obj = Player_obj;
3473 if (Viewer_mode & VM_OTHER_SHIP) {
3474 if (Player_ai->target_objnum != -1){
3475 Viewer_obj = &Objects[Player_ai->target_objnum];
3476 last_Viewer_objnum = Player_ai->target_objnum;
3478 Viewer_mode &= ~VM_OTHER_SHIP;
3479 last_Viewer_objnum = -1;
3482 last_Viewer_objnum = -1;
3485 if (Viewer_mode & VM_EXTERNAL) {
3488 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3489 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3491 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3493 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3494 vm_vec_normalize(&eye_dir);
3495 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3498 // Modify the orientation based on head orientation.
3499 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3501 } else if ( Viewer_mode & VM_CHASE ) {
3504 if ( Viewer_obj->phys_info.speed < 0.1 )
3505 move_dir = Viewer_obj->orient.v.fvec;
3507 move_dir = Viewer_obj->phys_info.vel;
3508 vm_vec_normalize(&move_dir);
3511 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3512 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3513 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3514 vm_vec_normalize(&eye_dir);
3516 // JAS: I added the following code because if you slew up using
3517 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3518 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3519 // call because the up and the forward vector are the same. I fixed
3520 // it by adding in a fraction of the right vector all the time to the
3522 vector tmp_up = Viewer_obj->orient.v.uvec;
3523 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3525 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3528 // Modify the orientation based on head orientation.
3529 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3530 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3531 *eye_pos = Camera_pos;
3533 ship * shipp = &Ships[Player_obj->instance];
3535 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3536 vm_vec_normalize(&eye_dir);
3537 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3540 // get an eye position based upon the correct type of object
3541 switch(Viewer_obj->type){
3543 // make a call to get the eye point for the player object
3544 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3547 // make a call to get the eye point for the player object
3548 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3554 #ifdef JOHNS_DEBUG_CODE
3555 john_debug_stuff(&eye_pos, &eye_orient);
3561 apply_hud_shake(eye_orient);
3563 // setup neb2 rendering
3564 neb2_render_setup(eye_pos, eye_orient);
3568 extern void ai_debug_render_stuff();
3571 int Game_subspace_effect = 0;
3572 DCF_BOOL( subspace, Game_subspace_effect );
3574 // Does everything needed to render a frame
3575 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3579 g3_start_frame(game_zbuffer);
3580 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3582 // maybe offset the HUD (jitter stuff)
3583 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3584 HUD_set_offsets(Viewer_obj, !dont_offset);
3586 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3587 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3588 // must be done before ships are rendered
3589 if ( MULTIPLAYER_CLIENT ) {
3590 shield_point_multi_setup();
3593 if ( Game_subspace_effect ) {
3594 stars_draw(0,0,0,1);
3596 stars_draw(1,1,1,0);
3599 obj_render_all(obj_render);
3600 beam_render_all(); // render all beam weapons
3601 particle_render_all(); // render particles after everything else.
3602 trail_render_all(); // render missilie trails after everything else.
3603 mflash_render_all(); // render all muzzle flashes
3605 // Why do we not show the shield effect in these modes? Seems ok.
3606 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3610 // render nebula lightning
3613 // render local player nebula
3614 neb2_render_player();
3617 ai_debug_render_stuff();
3620 #ifndef RELEASE_REAL
3621 // game_framerate_check();
3625 extern void snd_spew_debug_info();
3626 snd_spew_debug_info();
3629 //================ END OF 3D RENDERING STUFF ====================
3633 if( (Game_detail_flags & DETAIL_FLAG_HUD) && (!(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )) ) {
3634 hud_maybe_clear_head_area();
3635 anim_render_all(0, flFrametime);
3638 extern int Multi_display_netinfo;
3639 if(Multi_display_netinfo){
3640 extern void multi_display_netinfo();
3641 multi_display_netinfo();
3644 game_tst_frame_pre();
3647 do_timing_test(flFrametime);
3651 extern int OO_update_index;
3652 multi_rate_display(OO_update_index, 375, 0);
3657 extern void oo_display();
3664 //#define JOHNS_DEBUG_CODE 1
3666 #ifdef JOHNS_DEBUG_CODE
3667 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3669 //if ( key_pressed(SDLK_LSHIFT) )
3671 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3673 model_subsystem *turret = tsys->system_info;
3675 if (turret->type == SUBSYSTEM_TURRET ) {
3676 vector v.fvec, v.uvec;
3677 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3679 ship_model_start(tobj);
3681 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3682 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3683 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3685 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3687 ship_model_stop(tobj);
3697 // following function for dumping frames for purposes of building trailers.
3700 // function to toggle state of dumping every frame into PCX when playing the game
3701 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3705 if ( Debug_dump_frames == 0 ) {
3707 Debug_dump_frames = 15;
3708 Debug_dump_trigger = 0;
3709 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3710 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3713 Debug_dump_frames = 0;
3714 Debug_dump_trigger = 0;
3715 gr_dump_frame_stop();
3716 dc_printf( "Frame dumping is now OFF\n" );
3722 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3726 if ( Debug_dump_frames == 0 ) {
3728 Debug_dump_frames = 15;
3729 Debug_dump_trigger = 1;
3730 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3731 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3734 Debug_dump_frames = 0;
3735 Debug_dump_trigger = 0;
3736 gr_dump_frame_stop();
3737 dc_printf( "Frame dumping is now OFF\n" );
3743 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3747 if ( Debug_dump_frames == 0 ) {
3749 Debug_dump_frames = 30;
3750 Debug_dump_trigger = 0;
3751 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3752 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3755 Debug_dump_frames = 0;
3756 Debug_dump_trigger = 0;
3757 gr_dump_frame_stop();
3758 dc_printf( "Frame dumping is now OFF\n" );
3764 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3768 if ( Debug_dump_frames == 0 ) {
3770 Debug_dump_frames = 30;
3771 Debug_dump_trigger = 1;
3772 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3773 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3776 Debug_dump_frames = 0;
3777 Debug_dump_trigger = 0;
3778 gr_dump_frame_stop();
3779 dc_printf( "Triggered frame dumping is now OFF\n" );
3785 void game_maybe_dump_frame()
3787 if ( !Debug_dump_frames ){
3791 if( Debug_dump_trigger && !key_pressed(SDLK_q) ){
3798 Debug_dump_frame_num++;
3804 extern int Player_dead_state;
3806 // Flip the page and time how long it took.
3807 void game_flip_page_and_time_it()
3812 t1 = timer_get_fixed_seconds();
3814 t2 = timer_get_fixed_seconds();
3817 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3818 SDL_snprintf( transfer_text, SDL_arraysize(transfer_text), NOX("%d MB/s"), fixmuldiv(t,65,d) );
3825 void game_simulation_frame()
3827 // blow ships up in multiplayer dogfight
3828 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (f2fl(Missiontime) >= 2.0f) && !dogfight_blown){
3829 // blow up all non-player ships
3830 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3833 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3835 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 >= Num_ship_types)){
3836 moveup = GET_NEXT(moveup);
3839 shipp = &Ships[Objects[moveup->objnum].instance];
3840 sip = &Ship_info[shipp->ship_info_index];
3842 // only blow up small ships
3843 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3844 // function to simply explode a ship where it is currently at
3845 ship_self_destruct( &Objects[moveup->objnum] );
3848 moveup = GET_NEXT(moveup);
3854 // process AWACS stuff - do this first thing
3857 // single player, set Player hits_this_frame to 0
3858 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3859 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3860 Player->damage_this_burst = SDL_max(Player->damage_this_burst, 0.0f);
3864 supernova_process();
3865 if(supernova_active() >= 5){
3869 // fire targeting lasers now so that
3870 // 1 - created this frame
3871 // 2 - collide this frame
3872 // 3 - render this frame
3873 // 4 - ignored and deleted next frame
3874 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3876 ship_process_targeting_lasers();
3878 // do this here so that it works for multiplayer
3880 // get viewer direction
3881 int viewer_direction = PHYSICS_VIEWER_REAR;
3883 if(Viewer_mode == 0){
3884 viewer_direction = PHYSICS_VIEWER_FRONT;
3886 if(Viewer_mode & VM_PADLOCK_UP){
3887 viewer_direction = PHYSICS_VIEWER_UP;
3889 else if(Viewer_mode & VM_PADLOCK_REAR){
3890 viewer_direction = PHYSICS_VIEWER_REAR;
3892 else if(Viewer_mode & VM_PADLOCK_LEFT){
3893 viewer_direction = PHYSICS_VIEWER_LEFT;
3895 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3896 viewer_direction = PHYSICS_VIEWER_RIGHT;
3899 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3901 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3904 #define VM_PADLOCK_UP (1 << 7)
3905 #define VM_PADLOCK_REAR (1 << 8)
3906 #define VM_PADLOCK_LEFT (1 << 9)
3907 #define VM_PADLOCK_RIGHT (1 << 10)
3909 // evaluate mission departures and arrivals before we process all objects.
3910 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3912 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3913 // ships/wing packets.
3914 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3915 mission_parse_eval_stuff();
3918 // if we're an observer, move ourselves seperately from the standard physics
3919 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3920 obj_observer_move(flFrametime);
3923 // move all the objects now
3924 obj_move_all(flFrametime);
3926 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3927 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3928 // ship_check_cargo_all();
3929 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3930 mission_eval_goals();
3934 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3935 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3936 training_check_objectives();
3939 // do all interpolation now
3940 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3941 // client side processing of warping in effect stages
3942 multi_do_client_warp(flFrametime);
3944 // client side movement of an observer
3945 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3946 obj_observer_move(flFrametime);
3949 // move all objects - does interpolation now as well
3950 obj_move_all(flFrametime);
3953 // only process the message queue when the player is "in" the game
3954 if ( !Pre_player_entry ){
3955 message_queue_process(); // process any messages send to the player
3958 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3959 message_maybe_distort(); // maybe distort incoming message if comms damaged
3960 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3961 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3962 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3965 if(!(Game_mode & GM_STANDALONE_SERVER)){
3966 // process some stuff every frame (before frame is rendered)
3967 emp_process_local();
3969 hud_update_frame(); // update hud systems
3971 if (!physics_paused) {
3972 // Move particle system
3973 particle_move_all(flFrametime);
3975 // Move missile trails
3976 trail_move_all(flFrametime);
3978 // process muzzle flashes
3979 mflash_process_all();
3981 // Flash the gun flashes
3982 shipfx_flash_do_frame(flFrametime);
3984 shockwave_move_all(flFrametime); // update all the shockwaves
3987 // subspace missile strikes
3990 obj_snd_do_frame(); // update the object-linked persistant sounds
3991 game_maybe_update_sound_environment();
3992 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3994 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3996 if ( Game_subspace_effect ) {
3997 game_start_subspace_ambient_sound();
4003 // Maybe render and process the dead-popup
4004 void game_maybe_do_dead_popup(float frametime)
4006 if ( popupdead_is_active() ) {
4008 int choice = popupdead_do_frame(frametime);
4010 if ( Game_mode & GM_NORMAL ) {
4013 gameseq_post_event(GS_EVENT_ENTER_GAME);
4017 gameseq_post_event(GS_EVENT_END_GAME);
4021 gameseq_post_event(GS_EVENT_START_GAME);
4024 // this should only happen during a red alert mission
4027 SDL_assert(The_mission.red_alert);
4028 if(!The_mission.red_alert){
4029 gameseq_post_event(GS_EVENT_START_GAME);
4033 // choose the previous mission
4034 mission_campaign_previous_mission();
4036 gameseq_post_event(GS_EVENT_START_GAME);
4046 case POPUPDEAD_DO_MAIN_HALL:
4047 multi_quit_game(PROMPT_NONE,-1);
4050 case POPUPDEAD_DO_RESPAWN:
4051 multi_respawn_normal();
4052 event_music_player_respawn();
4055 case POPUPDEAD_DO_OBSERVER:
4056 multi_respawn_observer();
4057 event_music_player_respawn_as_observer();
4066 if ( leave_popup ) {
4072 // returns true if player is actually in a game_play stats
4073 int game_actually_playing()
4077 state = gameseq_get_state();
4078 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4084 // Draw the 2D HUD gauges
4085 void game_render_hud_2d()
4087 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4091 HUD_render_2d(flFrametime);
4095 // Draw the 3D-dependant HUD gauges
4096 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4098 g3_start_frame(0); // 0 = turn zbuffering off
4099 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4101 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4102 HUD_render_3d(flFrametime);
4106 game_sunspot_process(flFrametime);
4108 // Diminish the palette effect
4109 game_flash_diminish(flFrametime);
4117 int actually_playing;
4118 fix total_time1, total_time2;
4119 fix render2_time1=0, render2_time2=0;
4120 fix render3_time1=0, render3_time2=0;
4121 fix flip_time1=0, flip_time2=0;
4122 fix clear_time1=0, clear_time2=0;
4128 if (Framerate_delay) {
4129 int start_time = timer_get_milliseconds();
4130 while (timer_get_milliseconds() < start_time + Framerate_delay)
4136 demo_do_frame_start();
4138 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4143 // start timing frame
4144 timing_frame_start();
4146 total_time1 = timer_get_fixed_seconds();
4148 // var to hold which state we are in
4149 actually_playing = game_actually_playing();
4151 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4152 if (!(Game_mode & GM_STANDALONE_SERVER)){
4153 SDL_assert( OBJ_INDEX(Player_obj) >= 0 );
4157 if (Missiontime > Entry_delay_time){
4158 Pre_player_entry = 0;
4160 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4163 // Note: These are done even before the player enters, else buffers can overflow.
4164 if (! (Game_mode & GM_STANDALONE_SERVER)){
4168 shield_frame_init();
4170 if ( Player->control_mode != PCM_NORMAL )
4173 if ( !Pre_player_entry && actually_playing ) {
4174 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4176 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4177 game_process_keys();
4179 // don't read flying controls if we're playing a demo back
4180 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4181 read_player_controls( Player_obj, flFrametime);
4185 // if we're not the master, we may have to send the server-critical ship status button_info bits
4186 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4187 multi_maybe_send_ship_status();
4192 // Reset the whack stuff
4195 // These two lines must be outside of Pre_player_entry code,
4196 // otherwise too many lights are added.
4199 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4203 game_simulation_frame();
4205 // if not actually in a game play state, then return. This condition could only be true in
4206 // a multiplayer game.
4207 if ( !actually_playing ) {
4208 SDL_assert( Game_mode & GM_MULTIPLAYER );
4212 if (!Pre_player_entry) {
4213 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4214 clear_time1 = timer_get_fixed_seconds();
4215 // clear the screen to black
4217 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4221 clear_time2 = timer_get_fixed_seconds();
4222 render3_time1 = timer_get_fixed_seconds();
4223 game_render_frame_setup(&eye_pos, &eye_orient);
4224 game_render_frame( &eye_pos, &eye_orient );
4226 // save the eye position and orientation
4227 if ( Game_mode & GM_MULTIPLAYER ) {
4228 Net_player->s_info.eye_pos = eye_pos;
4229 Net_player->s_info.eye_orient = eye_orient;
4232 hud_show_target_model();
4234 // check to see if we should display the death died popup
4235 if(Game_mode & GM_DEAD_BLEW_UP){
4236 if(Game_mode & GM_MULTIPLAYER){
4237 // catch the situation where we're supposed to be warping out on this transition
4238 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4239 gameseq_post_event(GS_EVENT_DEBRIEF);
4240 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4241 Player_died_popup_wait = -1;
4245 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4246 Player_died_popup_wait = -1;
4252 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4253 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4254 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4255 if(!popupdead_is_active()){
4259 Player_multi_died_check = -1;
4263 render3_time2 = timer_get_fixed_seconds();
4264 render2_time1 = timer_get_fixed_seconds();
4267 game_get_framerate();
4268 game_show_framerate();
4270 game_show_time_left();
4272 // Draw the 2D HUD gauges
4273 if(supernova_active() < 3){
4274 game_render_hud_2d();
4277 game_set_view_clip();
4279 // Draw 3D HUD gauges
4280 game_render_hud_3d(&eye_pos, &eye_orient);
4284 render2_time2 = timer_get_fixed_seconds();
4286 // maybe render and process the dead popup
4287 game_maybe_do_dead_popup(flFrametime);
4289 // start timing frame
4290 timing_frame_stop();
4291 // timing_display(30, 10);
4293 // If a regular popup is active, don't flip (popup code flips)
4294 if( !popup_running_state() ){
4295 flip_time1 = timer_get_fixed_seconds();
4296 game_flip_page_and_time_it();
4297 flip_time2 = timer_get_fixed_seconds();
4301 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4304 game_show_standalone_framerate();
4308 game_do_training_checks();
4311 // process lightning (nebula only)
4314 total_time2 = timer_get_fixed_seconds();
4316 // Got some timing numbers
4317 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4318 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4319 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4320 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4321 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4324 demo_do_frame_end();
4326 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4332 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4333 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4334 // died. This resulted in screwed up death sequences.
4336 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4337 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4338 static int timer_paused=0;
4339 #if defined(TIMER_TEST) && !defined(NDEBUG)
4340 static int stop_count,start_count;
4341 static int time_stopped,time_started;
4343 int saved_timestamp_ticker = -1;
4345 void game_reset_time()
4347 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4351 // Last_time = timer_get_fixed_seconds();
4357 void game_stop_time()
4359 if (timer_paused==0) {
4361 time = timer_get_fixed_seconds();
4362 // Save how much time progressed so far in the frame so we can
4363 // use it when we unpause.
4364 Last_delta_time = time - Last_time;
4366 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4367 if (Last_delta_time < 0) {
4368 #if defined(TIMER_TEST) && !defined(NDEBUG)
4369 Int3(); //get Matt!!!!
4371 Last_delta_time = 0;
4373 #if defined(TIMER_TEST) && !defined(NDEBUG)
4374 time_stopped = time;
4377 // Stop the timer_tick stuff...
4378 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4379 saved_timestamp_ticker = timestamp_ticker;
4383 #if defined(TIMER_TEST) && !defined(NDEBUG)
4388 void game_start_time()
4391 SDL_assert(timer_paused >= 0);
4392 if (timer_paused==0) {
4394 time = timer_get_fixed_seconds();
4395 #if defined(TIMER_TEST) && !defined(NDEBUG)
4397 Int3(); //get Matt!!!!
4400 // Take current time, and set it backwards to account for time
4401 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4402 // will be correct when it goes to calculate the frametime next
4404 Last_time = time - Last_delta_time;
4405 #if defined(TIMER_TEST) && !defined(NDEBUG)
4406 time_started = time;
4409 // Restore the timer_tick stuff...
4410 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4411 SDL_assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4412 timestamp_ticker = saved_timestamp_ticker;
4413 saved_timestamp_ticker = -1;
4416 #if defined(TIMER_TEST) && !defined(NDEBUG)
4422 void game_set_frametime(int state)
4424 fix thistime = timer_get_fixed_seconds();
4427 if ( Last_time == 0 )
4428 Frametime = F1_0 / 30;
4430 Frametime = thistime - Last_time;
4432 // Frametime = F1_0 / 30;
4435 fix debug_frametime = Frametime; // Just used to display frametime.
4438 // If player hasn't entered mission yet, make frame take 1/4 second.
4439 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4442 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4444 fix frame_speed = F1_0 / Debug_dump_frames;
4446 if (Frametime > frame_speed ){
4447 nprintf(("warning","slow frame: %x\n",Frametime));
4450 thistime = timer_get_fixed_seconds();
4451 Frametime = thistime - Last_time;
4452 } while (Frametime < frame_speed );
4454 Frametime = frame_speed;
4458 if (Game_mode & GM_STANDALONE_SERVER) {
4459 // if we are just sitting idle then set fps to 10, otherwise jump up to
4461 if (state == GS_STATE_STANDALONE_MAIN) {
4464 frame_cap = Multi_options_g.std_framecap;
4467 frame_cap = Framerate_cap;
4470 SDL_assert( frame_cap > 0 );
4472 #ifndef __EMSCRIPTEN__
4473 // Cap the framerate so it doesn't get too high.
4477 cap = F1_0/frame_cap;
4478 if (Frametime < cap) {
4479 thistime = cap - Frametime;
4480 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4481 SDL_Delay( fl2i(f2fl(thistime) * 1000.0f) );
4483 thistime = timer_get_fixed_seconds();
4488 // If framerate is too low, cap it.
4489 if (Frametime > MAX_FRAMETIME) {
4491 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4493 Frametime = MAX_FRAMETIME;
4496 Frametime = fixmul(Frametime, Game_time_compression);
4498 Last_time = thistime;
4499 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4501 flFrametime = f2fl(Frametime);
4502 //if(!(Game_mode & GM_PLAYING_DEMO)){
4503 timestamp_inc(flFrametime);
4505 /* if ((Framecount > 0) && (Framecount < 10)) {
4506 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4511 // This is called from game_do_frame(), and from navmap_do_frame()
4512 void game_update_missiontime()
4514 // TODO JAS: Put in if and move this into game_set_frametime,
4515 // fix navmap to call game_stop/start_time
4516 //if ( !timer_paused )
4517 Missiontime += Frametime;
4520 void game_do_frame()
4522 game_set_frametime(GS_STATE_GAME_PLAY);
4523 game_update_missiontime();
4525 if (Game_mode & GM_STANDALONE_SERVER) {
4526 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4529 if ( game_single_step && (last_single_step == game_single_step) ) {
4530 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4531 while( key_checkch() == 0 )
4533 os_set_title( XSTR( "FreeSpace", 171) );
4534 Last_time = timer_get_fixed_seconds();
4537 last_single_step = game_single_step;
4539 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4540 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4544 Keep_mouse_centered = 0;
4545 monitor_update(); // Update monitor variables
4548 void multi_maybe_do_frame()
4550 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4555 int Joymouse_button_status = 0;
4557 // Flush all input devices
4565 Joymouse_button_status = 0;
4567 //mprintf(("Game flush!\n" ));
4570 // function for multiplayer only which calls game_do_state_common() when running the
4572 void game_do_dc_networking()
4574 SDL_assert( Game_mode & GM_MULTIPLAYER );
4576 game_do_state_common( gameseq_get_state() );
4579 // Call this whenever in a loop, or when you need to check for a keystroke.
4580 int game_check_key()
4586 // convert keypad enter to normal enter
4587 if ((k & KEY_MASK) == SDLK_KP_ENTER)
4588 k = (k & ~KEY_MASK) | SDLK_RETURN;
4593 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4595 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4596 static int Demo_show_trailer_timestamp = 0;
4598 void demo_reset_trailer_timer()
4600 Demo_show_trailer_timestamp = timer_get_milliseconds();
4603 void demo_maybe_show_trailer(int k)
4606 // if key pressed, reset demo trailer timer
4608 demo_reset_trailer_timer();
4612 // if mouse moved, reset demo trailer timer
4615 mouse_get_delta(&dx, &dy);
4616 if ( (dx > 0) || (dy > 0) ) {
4617 demo_reset_trailer_timer();
4621 // if joystick has moved, reset demo trailer timer
4624 joy_get_delta(&dx, &dy);
4625 if ( (dx > 0) || (dy > 0) ) {
4626 demo_reset_trailer_timer();
4630 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4631 // the low-level code. Ugly, I know... but was the simplest and most
4634 // if 30 seconds since last demo trailer time reset, launch movie
4635 if ( os_foreground() ) {
4636 int now = timer_get_milliseconds();
4637 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4638 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4640 movie_play( NOX("fstrailer2.mve") );
4641 demo_reset_trailer_timer();
4649 // same as game_check_key(), except this is used while actually in the game. Since there
4650 // generally are differences between game control keys and general UI keys, makes sense to
4651 // have seperate functions for each case. If you are not checking a game control while in a
4652 // mission, you should probably be using game_check_key() instead.
4657 if (!os_foreground()) {
4662 // If we're in a single player game, pause it.
4663 if (!(Game_mode & GM_MULTIPLAYER)){
4664 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4665 game_process_pause_key();
4672 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4673 demo_maybe_show_trailer(k);
4676 // Move the mouse cursor with the joystick.
4677 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4678 // Move the mouse cursor with the joystick
4682 joy_get_pos( &jx, &jy, &jz, &jr );
4684 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4685 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4688 mouse_get_real_pos( &mx, &my );
4689 mouse_set_pos( mx+dx, my+dy );
4694 m = mouse_down(MOUSE_LEFT_BUTTON);
4696 if ( j != Joymouse_button_status ) {
4697 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4698 Joymouse_button_status = j;
4700 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4701 } else if ( (!j) && (m) ) {
4702 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4707 // if we should be ignoring keys because of some multiplayer situations
4708 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4712 // If a popup is running, don't process all the Fn keys
4713 if( popup_active() ) {
4717 state = gameseq_get_state();
4719 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4722 case KEY_DEBUGGED + SDLK_BACKSPACE:
4727 launch_context_help();
4732 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4734 // don't allow f2 while warping out in multiplayer
4735 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4740 case GS_STATE_INITIAL_PLAYER_SELECT:
4741 case GS_STATE_OPTIONS_MENU:
4742 case GS_STATE_HUD_CONFIG:
4743 case GS_STATE_CONTROL_CONFIG:
4744 case GS_STATE_DEATH_DIED:
4745 case GS_STATE_DEATH_BLEW_UP:
4746 case GS_STATE_VIEW_MEDALS:
4750 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4757 // hotkey selection screen -- only valid from briefing and beyond.
4759 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
4760 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) ) {
4761 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4767 case KEY_DEBUGGED + SDLK_F3:
4768 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4771 case KEY_DEBUGGED + SDLK_F4:
4772 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4776 if(Game_mode & GM_MULTIPLAYER){
4777 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4778 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4782 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4783 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4789 case SDLK_ESCAPE | KEY_SHIFTED:
4790 // make sure to quit properly out of multiplayer
4791 if(Game_mode & GM_MULTIPLAYER){
4792 multi_quit_game(PROMPT_NONE);
4795 gameseq_post_event( GS_EVENT_QUIT_GAME );
4800 case KEY_DEBUGGED + SDLK_p:
4803 case SDLK_PRINTSCREEN:
4805 static int counter = 0;
4810 SDL_snprintf( tmp_name, SDL_arraysize(tmp_name), NOX("screen%02d"), counter );
4812 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4813 gr_print_screen(tmp_name);
4821 case KEY_SHIFTED | SDLK_RETURN: {
4823 #if !defined(NDEBUG)
4825 if ( Game_mode & GM_NORMAL ){
4829 // if we're in multiplayer mode, do some special networking
4830 if(Game_mode & GM_MULTIPLAYER){
4831 debug_console(game_do_dc_networking);
4838 if ( Game_mode & GM_NORMAL )
4852 gameseq_post_event(GS_EVENT_QUIT_GAME);
4855 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4858 void camera_set_position( vector *pos )
4863 void camera_set_orient( matrix *orient )
4865 Camera_orient = *orient;
4868 void camera_set_velocity( vector *vel, int instantaneous )
4870 Camera_desired_velocity.xyz.x = 0.0f;
4871 Camera_desired_velocity.xyz.y = 0.0f;
4872 Camera_desired_velocity.xyz.z = 0.0f;
4874 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4875 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4876 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4878 if ( instantaneous ) {
4879 Camera_velocity = Camera_desired_velocity;
4887 vector new_vel, delta_pos;
4889 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4890 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4891 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4893 Camera_velocity = new_vel;
4895 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4897 vm_vec_add2( &Camera_pos, &delta_pos );
4899 float ot = Camera_time+0.0f;
4901 Camera_time += flFrametime;
4903 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4906 tmp.xyz.z = 4.739f; // always go this fast forward.
4908 // pick x and y velocities so they are always on a
4909 // circle with a 25 m radius.
4911 float tmp_angle = frand()*PI2;
4913 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4914 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4916 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4918 //mprintf(( "Changing velocity!\n" ));
4919 camera_set_velocity( &tmp, 0 );
4922 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4923 vector tmp = ZERO_VECTOR;
4924 camera_set_velocity( &tmp, 0 );
4929 void end_demo_campaign_do()
4931 // go to upsell screens, which should drop back to the main hall
4932 gameseq_post_event(GS_EVENT_DEMO_UPSELL);
4935 // All code to process events. This is the only place
4936 // that you should change the state of the game.
4938 void game_process_event( int current_state, int event )
4940 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4943 case GS_EVENT_SIMULATOR_ROOM:
4944 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4947 case GS_EVENT_MAIN_MENU:
4948 gameseq_set_state(GS_STATE_MAIN_MENU);
4951 case GS_EVENT_OPTIONS_MENU:
4952 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4955 case GS_EVENT_BARRACKS_MENU:
4956 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4959 case GS_EVENT_TECH_MENU:
4960 gameseq_set_state(GS_STATE_TECH_MENU);
4963 case GS_EVENT_TRAINING_MENU:
4964 gameseq_set_state(GS_STATE_TRAINING_MENU);
4967 case GS_EVENT_START_GAME:
4968 Select_default_ship = 0;
4969 Player_multi_died_check = -1;
4970 gameseq_set_state(GS_STATE_CMD_BRIEF);
4973 case GS_EVENT_START_BRIEFING:
4974 gameseq_set_state(GS_STATE_BRIEFING);
4977 case GS_EVENT_DEBRIEF:
4978 // did we end the campaign in the main freespace 2 single player campaign?
4980 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace")) {
4982 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace2")) {
4984 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4986 gameseq_set_state(GS_STATE_DEBRIEF);
4989 Player_multi_died_check = -1;
4992 case GS_EVENT_SHIP_SELECTION:
4993 gameseq_set_state( GS_STATE_SHIP_SELECT );
4996 case GS_EVENT_WEAPON_SELECTION:
4997 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5000 case GS_EVENT_ENTER_GAME:
5002 // maybe start recording a demo
5004 demo_start_record("test.fsd");
5008 if (Game_mode & GM_MULTIPLAYER) {
5009 // if we're respawning, make sure we change the view mode so that the hud shows up
5010 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5014 gameseq_set_state(GS_STATE_GAME_PLAY);
5016 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5019 Player_multi_died_check = -1;
5021 // clear multiplayer button info
5022 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5024 Start_time = f2fl(timer_get_approx_seconds());
5026 mprintf(("Entering game at time = %7.3f\n", Start_time));
5030 case GS_EVENT_START_GAME_QUICK:
5031 Select_default_ship = 1;
5032 gameseq_post_event(GS_EVENT_ENTER_GAME);
5036 case GS_EVENT_END_GAME:
5037 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5038 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5039 gameseq_set_state(GS_STATE_MAIN_MENU);
5044 Player_multi_died_check = -1;
5047 case GS_EVENT_QUIT_GAME:
5048 main_hall_stop_music();
5049 main_hall_stop_ambient();
5051 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5052 if (current_state == GS_STATE_DEMO_UPSELL) {
5053 gameseq_set_state(GS_STATE_QUIT_GAME);
5055 gameseq_set_state(GS_STATE_DEMO_UPSELL);
5058 gameseq_set_state(GS_STATE_QUIT_GAME);
5061 Player_multi_died_check = -1;
5064 case GS_EVENT_GAMEPLAY_HELP:
5065 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5068 case GS_EVENT_PAUSE_GAME:
5069 gameseq_push_state(GS_STATE_GAME_PAUSED);
5072 case GS_EVENT_DEBUG_PAUSE_GAME:
5073 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5076 case GS_EVENT_TRAINING_PAUSE:
5077 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5080 case GS_EVENT_PREVIOUS_STATE:
5081 gameseq_pop_state();
5084 case GS_EVENT_TOGGLE_FULLSCREEN:
5085 gr_toggle_fullscreen();
5088 case GS_EVENT_TOGGLE_GLIDE:
5091 case GS_EVENT_LOAD_MISSION_MENU:
5094 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5095 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5098 case GS_EVENT_HUD_CONFIG:
5099 gameseq_push_state( GS_STATE_HUD_CONFIG );
5102 case GS_EVENT_CONTROL_CONFIG:
5103 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5106 case GS_EVENT_DEATH_DIED:
5107 gameseq_set_state( GS_STATE_DEATH_DIED );
5110 case GS_EVENT_DEATH_BLEW_UP:
5111 if ( current_state == GS_STATE_DEATH_DIED ) {
5112 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5113 event_music_player_death();
5115 // multiplayer clients set their extra check here
5116 if(Game_mode & GM_MULTIPLAYER){
5117 // set the multi died absolute last chance check
5118 Player_multi_died_check = time(NULL);
5121 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5125 case GS_EVENT_NEW_CAMPAIGN:
5126 if (!mission_load_up_campaign()){
5127 readyroom_continue_campaign();
5130 Player_multi_died_check = -1;
5133 case GS_EVENT_CAMPAIGN_CHEAT:
5134 if (!mission_load_up_campaign()){
5136 // bash campaign value
5137 extern char Main_hall_campaign_cheat[512];
5140 // look for the mission
5141 for(idx=0; idx<Campaign.num_missions; idx++){
5142 if(!SDL_strcasecmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5143 Campaign.next_mission = idx;
5144 Campaign.prev_mission = idx - 1;
5151 readyroom_continue_campaign();
5154 Player_multi_died_check = -1;
5157 case GS_EVENT_CAMPAIGN_ROOM:
5158 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5161 case GS_EVENT_CMD_BRIEF:
5162 gameseq_set_state(GS_STATE_CMD_BRIEF);
5165 case GS_EVENT_RED_ALERT:
5166 gameseq_set_state(GS_STATE_RED_ALERT);
5169 case GS_EVENT_CREDITS:
5170 gameseq_set_state( GS_STATE_CREDITS );
5173 case GS_EVENT_VIEW_MEDALS:
5174 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5177 case GS_EVENT_SHOW_GOALS:
5178 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5181 case GS_EVENT_HOTKEY_SCREEN:
5182 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5185 // multiplayer stuff follow these comments
5188 gameseq_set_state(GS_STATE_PXO);
5191 case GS_EVENT_PXO_HELP:
5192 gameseq_set_state(GS_STATE_PXO_HELP);
5195 case GS_EVENT_MULTI_JOIN_GAME:
5196 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5199 case GS_EVENT_MULTI_HOST_SETUP:
5200 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5203 case GS_EVENT_MULTI_CLIENT_SETUP:
5204 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5207 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5208 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5211 case GS_EVENT_MULTI_STD_WAIT:
5212 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5215 case GS_EVENT_STANDALONE_MAIN:
5216 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5219 case GS_EVENT_MULTI_PAUSE:
5220 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5223 case GS_EVENT_INGAME_PRE_JOIN:
5224 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5227 case GS_EVENT_EVENT_DEBUG:
5228 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5231 // Start a warpout where player automatically goes 70 no matter what
5232 // and can't cancel out of it.
5233 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5234 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5236 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5237 Player->saved_viewer_mode = Viewer_mode;
5238 Player->control_mode = PCM_WARPOUT_STAGE1;
5239 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5240 Warpout_time = 0.0f; // Start timer!
5243 case GS_EVENT_PLAYER_WARPOUT_START:
5244 if ( Player->control_mode != PCM_NORMAL ) {
5245 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5247 Player->saved_viewer_mode = Viewer_mode;
5248 Player->control_mode = PCM_WARPOUT_STAGE1;
5249 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5250 Warpout_time = 0.0f; // Start timer!
5251 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5255 case GS_EVENT_PLAYER_WARPOUT_STOP:
5256 if ( Player->control_mode != PCM_NORMAL ) {
5257 if ( !Warpout_forced ) { // cannot cancel forced warpout
5258 Player->control_mode = PCM_NORMAL;
5259 Viewer_mode = Player->saved_viewer_mode;
5260 hud_subspace_notify_abort();
5261 mprintf(( "Player put back to normal mode.\n" ));
5262 if ( Warpout_sound > -1 ) {
5263 snd_stop( Warpout_sound );
5270 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5271 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5272 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5273 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5275 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5276 shipfx_warpout_start( Player_obj );
5277 Player->control_mode = PCM_WARPOUT_STAGE2;
5278 Player->saved_viewer_mode = Viewer_mode;
5279 Viewer_mode |= VM_WARP_CHASE;
5281 vector tmp = Player_obj->pos;
5283 ship_get_eye( &tmp, &tmp_m, Player_obj );
5284 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5285 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5286 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5288 camera_set_position( &tmp );
5289 camera_set_orient( &Player_obj->orient );
5290 vector tmp_vel = { { { 0.0f, 5.1919f, 14.7f } } };
5292 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5293 camera_set_velocity( &tmp_vel, 1);
5297 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5298 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5299 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5300 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5302 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5303 Player->control_mode = PCM_WARPOUT_STAGE3;
5307 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5308 mprintf(( "Player warped out. Going to debriefing!\n" ));
5309 Player->control_mode = PCM_NORMAL;
5310 Viewer_mode = Player->saved_viewer_mode;
5313 // we have a special debriefing screen for multiplayer furballs
5314 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5315 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5317 // do the normal debriefing for all other situations
5319 gameseq_post_event(GS_EVENT_DEBRIEF);
5323 case GS_EVENT_STANDALONE_POSTGAME:
5324 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5327 case GS_EVENT_INITIAL_PLAYER_SELECT:
5328 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5331 case GS_EVENT_GAME_INIT:
5332 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5333 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5335 // see if the command line option has been set to use the last pilot, and act acoordingly
5336 if( player_select_get_last_pilot() ) {
5337 // always enter the main menu -- do the automatic network startup stuff elsewhere
5338 // so that we still have valid checks for networking modes, etc.
5339 gameseq_set_state(GS_STATE_MAIN_MENU);
5341 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5346 case GS_EVENT_MULTI_MISSION_SYNC:
5347 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5350 case GS_EVENT_MULTI_START_GAME:
5351 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5354 case GS_EVENT_MULTI_HOST_OPTIONS:
5355 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5358 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5359 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5362 case GS_EVENT_TEAM_SELECT:
5363 gameseq_set_state(GS_STATE_TEAM_SELECT);
5366 case GS_EVENT_END_CAMPAIGN:
5367 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5370 case GS_EVENT_END_DEMO:
5371 gameseq_set_state(GS_STATE_END_DEMO);
5374 case GS_EVENT_LOOP_BRIEF:
5375 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5378 case GS_EVENT_DEMO_UPSELL:
5379 gameseq_set_state(GS_STATE_DEMO_UPSELL);
5388 // Called when a state is being left.
5389 // The current state is still at old_state, but as soon as
5390 // this function leaves, then the current state will become
5391 // new state. You should never try to change the state
5392 // in here... if you think you need to, you probably really
5393 // need to post an event, not change the state.
5394 void game_leave_state( int old_state, int new_state )
5396 int end_mission = 1;
5398 switch (new_state) {
5399 case GS_STATE_GAME_PAUSED:
5400 case GS_STATE_DEBUG_PAUSED:
5401 case GS_STATE_OPTIONS_MENU:
5402 case GS_STATE_CONTROL_CONFIG:
5403 case GS_STATE_MISSION_LOG_SCROLLBACK:
5404 case GS_STATE_DEATH_DIED:
5405 case GS_STATE_SHOW_GOALS:
5406 case GS_STATE_HOTKEY_SCREEN:
5407 case GS_STATE_MULTI_PAUSED:
5408 case GS_STATE_TRAINING_PAUSED:
5409 case GS_STATE_EVENT_DEBUG:
5410 case GS_STATE_GAMEPLAY_HELP:
5411 end_mission = 0; // these events shouldn't end a mission
5415 switch (old_state) {
5416 case GS_STATE_BRIEFING:
5417 brief_stop_voices();
5418 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5419 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5420 && (new_state != GS_STATE_TEAM_SELECT) ){
5421 common_select_close();
5422 if ( new_state == GS_STATE_MAIN_MENU ) {
5423 freespace_stop_mission();
5427 // COMMAND LINE OPTION
5428 if (Cmdline_multi_stream_chat_to_file){
5429 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5430 cfclose(Multi_chat_stream);
5434 case GS_STATE_DEBRIEF:
5435 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5440 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5441 multi_df_debrief_close();
5444 case GS_STATE_LOAD_MISSION_MENU:
5447 case GS_STATE_SIMULATOR_ROOM:
5451 case GS_STATE_CAMPAIGN_ROOM:
5452 campaign_room_close();
5455 case GS_STATE_CMD_BRIEF:
5456 if (new_state == GS_STATE_OPTIONS_MENU) {
5461 if (new_state == GS_STATE_MAIN_MENU)
5462 freespace_stop_mission();
5467 case GS_STATE_RED_ALERT:
5471 case GS_STATE_SHIP_SELECT:
5472 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5473 new_state != GS_STATE_HOTKEY_SCREEN &&
5474 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5475 common_select_close();
5476 if ( new_state == GS_STATE_MAIN_MENU ) {
5477 freespace_stop_mission();
5482 case GS_STATE_WEAPON_SELECT:
5483 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5484 new_state != GS_STATE_HOTKEY_SCREEN &&
5485 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5486 common_select_close();
5487 if ( new_state == GS_STATE_MAIN_MENU ) {
5488 freespace_stop_mission();
5493 case GS_STATE_TEAM_SELECT:
5494 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5495 new_state != GS_STATE_HOTKEY_SCREEN &&
5496 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5497 common_select_close();
5498 if ( new_state == GS_STATE_MAIN_MENU ) {
5499 freespace_stop_mission();
5504 case GS_STATE_MAIN_MENU:
5505 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5512 case GS_STATE_OPTIONS_MENU:
5513 //game_start_time();
5514 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5515 multi_join_clear_game_list();
5517 options_menu_close();
5520 case GS_STATE_BARRACKS_MENU:
5521 if(new_state != GS_STATE_VIEW_MEDALS){
5526 case GS_STATE_MISSION_LOG_SCROLLBACK:
5527 hud_scrollback_close();
5530 case GS_STATE_TRAINING_MENU:
5531 training_menu_close();
5534 case GS_STATE_GAME_PLAY:
5535 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5536 player_save_target_and_weapon_link_prefs();
5537 game_stop_looped_sounds();
5540 sound_env_disable();
5541 joy_ff_stop_effects();
5543 // stop game time under certain conditions
5544 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5549 // shut down any recording or playing demos
5554 // when in multiplayer and going back to the main menu, send a leave game packet
5555 // right away (before calling stop mission). stop_mission was taking to long to
5556 // close mission down and I want people to get notified ASAP.
5557 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5558 multi_quit_game(PROMPT_NONE);
5561 freespace_stop_mission();
5562 Game_time_compression = F1_0;
5566 case GS_STATE_TECH_MENU:
5570 case GS_STATE_TRAINING_PAUSED:
5571 Training_num_lines = 0;
5572 // fall through to GS_STATE_GAME_PAUSED
5574 case GS_STATE_GAME_PAUSED:
5576 if ( end_mission ) {
5581 case GS_STATE_DEBUG_PAUSED:
5584 pause_debug_close();
5588 case GS_STATE_HUD_CONFIG:
5592 // join/start a game
5593 case GS_STATE_MULTI_JOIN_GAME:
5594 if(new_state != GS_STATE_OPTIONS_MENU){
5595 multi_join_game_close();
5599 case GS_STATE_MULTI_HOST_SETUP:
5600 case GS_STATE_MULTI_CLIENT_SETUP:
5601 // if this is just the host going into the options screen, don't do anything
5602 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5606 // close down the proper state
5607 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5608 multi_create_game_close();
5610 multi_game_client_setup_close();
5613 // COMMAND LINE OPTION
5614 if (Cmdline_multi_stream_chat_to_file){
5615 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5616 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5617 cfclose(Multi_chat_stream);
5622 case GS_STATE_CONTROL_CONFIG:
5623 control_config_close();
5626 case GS_STATE_DEATH_DIED:
5627 Game_mode &= ~GM_DEAD_DIED;
5629 // early end while respawning or blowing up in a multiplayer game
5630 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5632 freespace_stop_mission();
5636 case GS_STATE_DEATH_BLEW_UP:
5637 Game_mode &= ~GM_DEAD_BLEW_UP;
5639 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5640 // to determine if I should do anything.
5641 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5643 freespace_stop_mission();
5646 // if we are not respawing as an observer or as a player, our new state will not
5647 // be gameplay state.
5648 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5649 game_stop_time(); // hasn't been called yet!!
5650 freespace_stop_mission();
5656 case GS_STATE_CREDITS:
5660 case GS_STATE_VIEW_MEDALS:
5664 case GS_STATE_SHOW_GOALS:
5665 mission_show_goals_close();
5668 case GS_STATE_HOTKEY_SCREEN:
5669 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5670 mission_hotkey_close();
5674 case GS_STATE_MULTI_MISSION_SYNC:
5675 // if we're moving into the options menu, don't do anything
5676 if(new_state == GS_STATE_OPTIONS_MENU){
5680 SDL_assert( Game_mode & GM_MULTIPLAYER );
5682 if ( new_state == GS_STATE_GAME_PLAY ){
5683 // palette_restore_palette();
5685 // change a couple of flags to indicate our state!!!
5686 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5687 send_netplayer_update_packet();
5689 // set the game mode
5690 Game_mode |= GM_IN_MISSION;
5694 case GS_STATE_VIEW_CUTSCENES:
5695 cutscenes_screen_close();
5698 case GS_STATE_MULTI_STD_WAIT:
5699 multi_standalone_wait_close();
5702 case GS_STATE_STANDALONE_MAIN:
5703 standalone_main_close();
5704 if(new_state == GS_STATE_MULTI_STD_WAIT){
5705 init_multiplayer_stats();
5709 case GS_STATE_MULTI_PAUSED:
5710 // if ( end_mission ){
5715 case GS_STATE_INGAME_PRE_JOIN:
5716 multi_ingame_select_close();
5719 case GS_STATE_STANDALONE_POSTGAME:
5720 multi_standalone_postgame_close();
5723 case GS_STATE_INITIAL_PLAYER_SELECT:
5724 player_select_close();
5727 case GS_STATE_MULTI_START_GAME:
5728 multi_start_game_close();
5731 case GS_STATE_MULTI_HOST_OPTIONS:
5732 multi_host_options_close();
5735 case GS_STATE_END_OF_CAMPAIGN:
5736 mission_campaign_end_close();
5739 case GS_STATE_LOOP_BRIEF:
5744 if (new_state != GS_STATE_PXO_HELP) {
5749 case GS_STATE_PXO_HELP:
5750 multi_pxo_help_close();
5753 case GS_STATE_DEMO_UPSELL:
5754 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5755 demo_upsell_close();
5761 // Called when a state is being entered.
5762 // The current state is set to the state we're entering at
5763 // this point, and old_state is set to the state we're coming
5764 // from. You should never try to change the state
5765 // in here... if you think you need to, you probably really
5766 // need to post an event, not change the state.
5768 void game_enter_state( int old_state, int new_state )
5770 switch (new_state) {
5771 case GS_STATE_MAIN_MENU:
5772 // in multiplayer mode, be sure that we are not doing networking anymore.
5773 if ( Game_mode & GM_MULTIPLAYER ) {
5774 SDL_assert( Net_player != NULL );
5775 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5778 Game_time_compression = F1_0;
5780 // determine which ship this guy is currently based on
5781 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5784 if (Player->on_bastion) {
5792 case GS_STATE_BRIEFING:
5793 main_hall_stop_music();
5794 main_hall_stop_ambient();
5796 if (Game_mode & GM_NORMAL) {
5797 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5798 // MWA: or from options or hotkey screens
5799 // JH: or if the command brief state already did this
5800 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5801 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5802 && (old_state != GS_STATE_CMD_BRIEF) ) {
5803 if ( !game_start_mission() ) // this should put us into a new state on failure!
5807 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5808 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5809 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5811 Game_time_compression = F1_0;
5813 if ( red_alert_mission() ) {
5814 gameseq_post_event(GS_EVENT_RED_ALERT);
5821 case GS_STATE_DEBRIEF:
5822 game_stop_looped_sounds();
5823 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5824 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5829 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5830 multi_df_debrief_init();
5833 case GS_STATE_LOAD_MISSION_MENU:
5836 case GS_STATE_SIMULATOR_ROOM:
5840 case GS_STATE_CAMPAIGN_ROOM:
5841 campaign_room_init();
5844 case GS_STATE_RED_ALERT:
5845 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5849 case GS_STATE_CMD_BRIEF: {
5850 int team_num = 0; // team number used as index for which cmd brief to use.
5852 if (old_state == GS_STATE_OPTIONS_MENU) {
5856 main_hall_stop_music();
5857 main_hall_stop_ambient();
5859 if (Game_mode & GM_NORMAL) {
5860 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5861 // MWA: or from options or hotkey screens
5862 // JH: or if the command brief state already did this
5863 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5864 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5865 if ( !game_start_mission() ) // this should put us into a new state on failure!
5870 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5871 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5872 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5874 cmd_brief_init(team_num);
5880 case GS_STATE_SHIP_SELECT:
5884 case GS_STATE_WEAPON_SELECT:
5885 weapon_select_init();
5888 case GS_STATE_TEAM_SELECT:
5892 case GS_STATE_GAME_PAUSED:
5897 case GS_STATE_DEBUG_PAUSED:
5898 // game_stop_time();
5899 // os_set_title("FreeSpace - PAUSED");
5902 case GS_STATE_TRAINING_PAUSED:
5909 case GS_STATE_OPTIONS_MENU:
5911 options_menu_init();
5914 case GS_STATE_GAME_PLAY:
5915 // coming from the gameplay state or the main menu, we might need to load the mission
5916 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5917 if ( !game_start_mission() ) // this should put us into a new state.
5922 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5923 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5924 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5925 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5926 (old_state == GS_STATE_WEAPON_SELECT) || (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_MULTI_STD_WAIT) || (old_state == GS_STATE_SIMULATOR_ROOM)) ) {
5927 // JAS: Used to do all paging here.
5931 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5935 main_hall_stop_music();
5936 main_hall_stop_ambient();
5937 event_music_first_pattern(); // start the first pattern
5940 // special code that restores player ship selection and weapons loadout when doing a quick start
5941 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY)) ) {
5942 if ( !SDL_strcasecmp(Player_loadout.filename, Game_current_mission_filename) ) {
5943 wss_direct_restore_loadout();
5947 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5948 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5949 event_music_first_pattern(); // start the first pattern
5952 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5953 event_music_first_pattern(); // start the first pattern
5955 player_restore_target_and_weapon_link_prefs();
5957 Game_mode |= GM_IN_MISSION;
5960 // required to truely make mouse deltas zeroed in debug mouse code
5961 if (!Is_standalone) {
5962 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5968 // only start time if in single player, or coming from multi wait state
5971 (Game_mode & GM_NORMAL) &&
5972 (old_state != GS_STATE_VIEW_CUTSCENES)
5974 (Game_mode & GM_MULTIPLAYER) && (
5975 (old_state == GS_STATE_MULTI_PAUSED) ||
5976 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5982 // when coming from the multi paused state, reset the timestamps
5983 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5984 multi_reset_timestamps();
5987 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5988 // initialize all object update details
5989 multi_oo_gameplay_init();
5992 // under certain circumstances, the server should reset the object update rate limiting stuff
5993 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5994 ((old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC)) ){
5996 // reinitialize the rate limiting system for all clients
5997 multi_oo_rate_init_all();
6000 // multiplayer clients should always re-initialize their control info rate limiting system
6001 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6002 multi_oo_rate_init_all();
6006 if(Game_mode & GM_MULTIPLAYER){
6007 multi_ping_reset_players();
6010 Game_subspace_effect = 0;
6011 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6012 Game_subspace_effect = 1;
6013 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6014 game_start_subspace_ambient_sound();
6018 sound_env_set(&Game_sound_env);
6019 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6021 // clear multiplayer button info i
6022 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6025 case GS_STATE_HUD_CONFIG:
6029 case GS_STATE_MULTI_JOIN_GAME:
6030 multi_join_clear_game_list();
6032 if (old_state != GS_STATE_OPTIONS_MENU) {
6033 multi_join_game_init();
6038 case GS_STATE_MULTI_HOST_SETUP:
6039 // don't reinitialize if we're coming back from the host options screen
6040 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6041 multi_create_game_init();
6046 case GS_STATE_MULTI_CLIENT_SETUP:
6047 if (old_state != GS_STATE_OPTIONS_MENU) {
6048 multi_game_client_setup_init();
6053 case GS_STATE_CONTROL_CONFIG:
6054 control_config_init();
6057 case GS_STATE_TECH_MENU:
6061 case GS_STATE_BARRACKS_MENU:
6062 if(old_state != GS_STATE_VIEW_MEDALS){
6067 case GS_STATE_MISSION_LOG_SCROLLBACK:
6068 hud_scrollback_init();
6071 case GS_STATE_DEATH_DIED:
6072 Player_died_time = timestamp(10);
6074 if(!(Game_mode & GM_MULTIPLAYER)){
6075 player_show_death_message();
6077 Game_mode |= GM_DEAD_DIED;
6080 case GS_STATE_DEATH_BLEW_UP:
6081 if ( !popupdead_is_active() ) {
6082 Player_ai->target_objnum = -1;
6085 // stop any local EMP effect
6088 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6089 Game_mode |= GM_DEAD_BLEW_UP;
6090 Show_viewing_from_self = 0;
6092 // timestamp how long we should wait before displaying the died popup
6093 if ( !popupdead_is_active() ) {
6094 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6098 case GS_STATE_GAMEPLAY_HELP:
6099 gameplay_help_init();
6102 case GS_STATE_CREDITS:
6103 main_hall_stop_music();
6104 main_hall_stop_ambient();
6108 case GS_STATE_VIEW_MEDALS:
6109 medal_main_init(Player);
6112 case GS_STATE_SHOW_GOALS:
6113 mission_show_goals_init();
6116 case GS_STATE_HOTKEY_SCREEN:
6117 mission_hotkey_init();
6120 case GS_STATE_MULTI_MISSION_SYNC:
6121 // if we're coming from the options screen, don't do any
6122 if(old_state == GS_STATE_OPTIONS_MENU){
6126 switch(Multi_sync_mode){
6127 case MULTI_SYNC_PRE_BRIEFING:
6128 // if moving from game forming to the team select state
6131 case MULTI_SYNC_POST_BRIEFING:
6132 // if moving from briefing into the mission itself
6135 // tell everyone that we're now loading data
6136 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6137 send_netplayer_update_packet();
6139 // JAS: Used to do all paging here!!!!
6141 Net_player->state = NETPLAYER_STATE_WAITING;
6142 send_netplayer_update_packet();
6144 Game_time_compression = F1_0;
6146 case MULTI_SYNC_INGAME:
6152 case GS_STATE_VIEW_CUTSCENES:
6153 cutscenes_screen_init();
6156 case GS_STATE_MULTI_STD_WAIT:
6157 multi_standalone_wait_init();
6160 case GS_STATE_STANDALONE_MAIN:
6161 // don't initialize if we're coming from one of these 2 states unless there are no
6162 // players left (reset situation)
6163 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6164 standalone_main_init();
6168 case GS_STATE_MULTI_PAUSED:
6172 case GS_STATE_INGAME_PRE_JOIN:
6173 multi_ingame_select_init();
6176 case GS_STATE_STANDALONE_POSTGAME:
6177 multi_standalone_postgame_init();
6180 case GS_STATE_INITIAL_PLAYER_SELECT:
6181 player_select_init();
6184 case GS_STATE_MULTI_START_GAME:
6185 multi_start_game_init();
6188 case GS_STATE_MULTI_HOST_OPTIONS:
6189 multi_host_options_init();
6192 case GS_STATE_END_OF_CAMPAIGN:
6193 mission_campaign_end_init();
6196 case GS_STATE_LOOP_BRIEF:
6201 if (old_state != GS_STATE_PXO_HELP) {
6203 // TODO: use_last_channel?
6209 case GS_STATE_PXO_HELP:
6210 multi_pxo_help_init();
6213 case GS_STATE_DEMO_UPSELL:
6214 #if defined(FS2_DEMO) || defined(FS1_DEMO)
6215 demo_upsell_init(old_state == GS_STATE_END_DEMO);
6222 // do stuff that may need to be done regardless of state
6223 void game_do_state_common(int state,int no_networking)
6225 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6226 snd_do_frame(); // update sound system
6227 event_music_do_frame(); // music needs to play across many states
6229 multi_log_process();
6231 // bail if state is invalid
6233 Game_do_state_should_skip = 1;
6237 if (no_networking) {
6241 // maybe do a multiplayer frame based on game mode and state type
6242 if (Game_mode & GM_MULTIPLAYER) {
6244 case GS_STATE_OPTIONS_MENU:
6245 case GS_STATE_GAMEPLAY_HELP:
6246 case GS_STATE_HOTKEY_SCREEN:
6247 case GS_STATE_HUD_CONFIG:
6248 case GS_STATE_CONTROL_CONFIG:
6249 case GS_STATE_MISSION_LOG_SCROLLBACK:
6250 case GS_STATE_SHOW_GOALS:
6251 case GS_STATE_VIEW_CUTSCENES:
6252 case GS_STATE_EVENT_DEBUG:
6253 multi_maybe_do_frame();
6257 game_do_networking();
6261 // Called once a frame.
6262 // You should never try to change the state
6263 // in here... if you think you need to, you probably really
6264 // need to post an event, not change the state.
6265 int Game_do_state_should_skip = 0;
6266 void game_do_state(int state)
6268 // always lets the do_state_common() function determine if the state should be skipped
6269 Game_do_state_should_skip = 0;
6271 // legal to set the should skip state anywhere in this function
6272 game_do_state_common(state); // do stuff that may need to be done regardless of state
6274 if(Game_do_state_should_skip){
6279 case GS_STATE_MAIN_MENU:
6280 game_set_frametime(GS_STATE_MAIN_MENU);
6281 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6284 main_hall_do(flFrametime);
6288 case GS_STATE_OPTIONS_MENU:
6289 game_set_frametime(GS_STATE_OPTIONS_MENU);
6290 options_menu_do_frame(flFrametime);
6293 case GS_STATE_BARRACKS_MENU:
6294 game_set_frametime(GS_STATE_BARRACKS_MENU);
6295 barracks_do_frame(flFrametime);
6298 case GS_STATE_TRAINING_MENU:
6299 game_set_frametime(GS_STATE_TRAINING_MENU);
6300 training_menu_do_frame(flFrametime);
6303 case GS_STATE_TECH_MENU:
6304 game_set_frametime(GS_STATE_TECH_MENU);
6305 techroom_do_frame(flFrametime);
6308 case GS_STATE_GAMEPLAY_HELP:
6309 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6310 gameplay_help_do_frame(flFrametime);
6313 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6317 case GS_STATE_GAME_PAUSED:
6321 case GS_STATE_DEBUG_PAUSED:
6323 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6328 case GS_STATE_TRAINING_PAUSED:
6329 game_training_pause_do();
6332 case GS_STATE_LOAD_MISSION_MENU:
6336 case GS_STATE_BRIEFING:
6337 game_set_frametime(GS_STATE_BRIEFING);
6338 brief_do_frame(flFrametime);
6341 case GS_STATE_DEBRIEF:
6342 game_set_frametime(GS_STATE_DEBRIEF);
6343 debrief_do_frame(flFrametime);
6346 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6347 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6348 multi_df_debrief_do();
6351 case GS_STATE_SHIP_SELECT:
6352 game_set_frametime(GS_STATE_SHIP_SELECT);
6353 ship_select_do(flFrametime);
6356 case GS_STATE_WEAPON_SELECT:
6357 game_set_frametime(GS_STATE_WEAPON_SELECT);
6358 weapon_select_do(flFrametime);
6361 case GS_STATE_MISSION_LOG_SCROLLBACK:
6362 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6363 hud_scrollback_do_frame(flFrametime);
6366 case GS_STATE_HUD_CONFIG:
6367 game_set_frametime(GS_STATE_HUD_CONFIG);
6368 hud_config_do_frame(flFrametime);
6371 case GS_STATE_MULTI_JOIN_GAME:
6372 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6373 multi_join_game_do_frame();
6376 case GS_STATE_MULTI_HOST_SETUP:
6377 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6378 multi_create_game_do();
6381 case GS_STATE_MULTI_CLIENT_SETUP:
6382 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6383 multi_game_client_setup_do_frame();
6386 case GS_STATE_CONTROL_CONFIG:
6387 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6388 control_config_do_frame(flFrametime);
6391 case GS_STATE_DEATH_DIED:
6395 case GS_STATE_DEATH_BLEW_UP:
6399 case GS_STATE_SIMULATOR_ROOM:
6400 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6401 sim_room_do_frame(flFrametime);
6404 case GS_STATE_CAMPAIGN_ROOM:
6405 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6406 campaign_room_do_frame(flFrametime);
6409 case GS_STATE_RED_ALERT:
6410 game_set_frametime(GS_STATE_RED_ALERT);
6411 red_alert_do_frame(flFrametime);
6414 case GS_STATE_CMD_BRIEF:
6415 game_set_frametime(GS_STATE_CMD_BRIEF);
6416 cmd_brief_do_frame(flFrametime);
6419 case GS_STATE_CREDITS:
6420 game_set_frametime(GS_STATE_CREDITS);
6421 credits_do_frame(flFrametime);
6424 case GS_STATE_VIEW_MEDALS:
6425 game_set_frametime(GS_STATE_VIEW_MEDALS);
6429 case GS_STATE_SHOW_GOALS:
6430 game_set_frametime(GS_STATE_SHOW_GOALS);
6431 mission_show_goals_do_frame(flFrametime);
6434 case GS_STATE_HOTKEY_SCREEN:
6435 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6436 mission_hotkey_do_frame(flFrametime);
6439 case GS_STATE_VIEW_CUTSCENES:
6440 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6441 cutscenes_screen_do_frame();
6444 case GS_STATE_MULTI_STD_WAIT:
6445 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6446 multi_standalone_wait_do();
6449 case GS_STATE_STANDALONE_MAIN:
6450 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6451 standalone_main_do();
6454 case GS_STATE_MULTI_PAUSED:
6455 game_set_frametime(GS_STATE_MULTI_PAUSED);
6459 case GS_STATE_TEAM_SELECT:
6460 game_set_frametime(GS_STATE_TEAM_SELECT);
6464 case GS_STATE_INGAME_PRE_JOIN:
6465 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6466 multi_ingame_select_do();
6469 case GS_STATE_EVENT_DEBUG:
6471 game_set_frametime(GS_STATE_EVENT_DEBUG);
6472 game_show_event_debug(flFrametime);
6476 case GS_STATE_STANDALONE_POSTGAME:
6477 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6478 multi_standalone_postgame_do();
6481 case GS_STATE_INITIAL_PLAYER_SELECT:
6482 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6486 case GS_STATE_MULTI_MISSION_SYNC:
6487 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6491 case GS_STATE_MULTI_START_GAME:
6492 game_set_frametime(GS_STATE_MULTI_START_GAME);
6493 multi_start_game_do();
6496 case GS_STATE_MULTI_HOST_OPTIONS:
6497 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6498 multi_host_options_do();
6501 case GS_STATE_END_OF_CAMPAIGN:
6502 mission_campaign_end_do();
6505 case GS_STATE_END_DEMO:
6506 game_set_frametime(GS_STATE_END_DEMO);
6507 end_demo_campaign_do();
6510 case GS_STATE_LOOP_BRIEF:
6511 game_set_frametime(GS_STATE_LOOP_BRIEF);
6516 game_set_frametime(GS_STATE_PXO);
6520 case GS_STATE_PXO_HELP:
6521 game_set_frametime(GS_STATE_PXO_HELP);
6522 multi_pxo_help_do();
6525 case GS_STATE_DEMO_UPSELL:
6526 #if defined(FS2_DEMO) || defined(FS1_DEMO)
6527 game_set_frametime(GS_STATE_DEMO_UPSELL);
6532 } // end switch(gs_current_state)
6536 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6537 int game_do_ram_check(int ram_in_mbytes)
6539 if ( ram_in_mbytes < 30 ) {
6540 int allowed_to_run = 1;
6541 if ( ram_in_mbytes < 25 ) {
6547 if ( allowed_to_run ) {
6548 SDL_MessageBoxData mboxd;
6549 SDL_MessageBoxButtonData mboxbuttons[2];
6552 // not a translated string, but it's too long and smartdrv isn't
6553 // really a thing for any OS we now support :p
6554 // sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run. If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE). Any memory allocated to SmartDrive is not usable by applications\n\nPress 'OK' to continue running with less than the minimum required memory\n", 193), ram_in_mbytes, ram_in_mbytes);
6555 SDL_snprintf( tmp, SDL_arraysize(tmp), "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run.\n\nPress 'OK' to continue running with less than the minimum required memory.\n", ram_in_mbytes);
6557 mboxbuttons[0].buttonid = 0;
6558 mboxbuttons[0].text = XSTR("Ok", 503);
6559 mboxbuttons[0].flags = 0;
6561 mboxbuttons[1].buttonid = 1;
6562 mboxbuttons[1].text = XSTR("Cancel", 504);
6563 mboxbuttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
6565 mboxd.flags = SDL_MESSAGEBOX_ERROR;
6566 mboxd.title = XSTR( "Not Enough RAM", 194);
6567 mboxd.message = tmp;
6568 mboxd.numbuttons = 2;
6569 mboxd.buttons = mboxbuttons;
6570 mboxd.window = NULL;
6571 mboxd.colorScheme = NULL;
6573 SDL_ShowMessageBox(&mboxd, &msgbox_rval);
6575 if ( msgbox_rval == 1 ) {
6579 // not a translated string, but it's too long and smartdrv isn't
6580 // really a thing for any OS we now support :p
6581 // sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run. If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE). Any memory allocated to SmartDrive is not usable by applications\n", 195), ram_in_mbytes, ram_in_mbytes);
6582 SDL_snprintf( tmp, SDL_arraysize(tmp), "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run.\n", ram_in_mbytes);
6584 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough RAM", 194), tmp, NULL);
6593 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6594 // If so, copy it over and remove the update directory.
6595 void game_maybe_update_launcher(char *exe_dir)
6600 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6604 int sub_total_destroyed = 0;
6608 // get the total for all his children
6609 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6610 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6613 // find the # of faces for this _individual_ object
6614 total = submodel_get_num_polys(model_num, sm);
6615 if(strstr(pm->submodel[sm].name, "-destroyed")){
6616 sub_total_destroyed = total;
6620 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6623 *out_total += total + sub_total;
6624 *out_destroyed_total += sub_total_destroyed;
6627 #define BAIL() do { int x; for(x=0; x<num_files; x++){ if(pof_list[x] != NULL){free(pof_list[x]); pof_list[x] = NULL;}} return;} while(0);
6628 void game_spew_pof_info()
6630 char *pof_list[1000];
6633 int idx, model_num, i, j;
6635 int total, root_total, model_total, destroyed_total, counted;
6639 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6641 // spew info on all the pofs
6647 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6652 for(idx=0; idx<num_files; idx++, counted++){
6653 SDL_snprintf(str, SDL_arraysize(str), "%s.pof", pof_list[idx]);
6654 model_num = model_load(str, 0, NULL);
6656 pm = model_get(model_num);
6658 // if we have a real model
6663 // go through and print all raw submodels
6664 cfputs("RAW\n", out);
6667 for (i=0; i<pm->n_models; i++) {
6668 total = submodel_get_num_polys(model_num, i);
6670 model_total += total;
6671 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6674 SDL_snprintf(str, SDL_arraysize(str), "Model total %d\n", model_total);
6677 // now go through and do it by LOD
6678 cfputs("BY LOD\n\n", out);
6679 for(i=0; i<pm->n_detail_levels; i++){
6680 SDL_snprintf(str, SDL_arraysize(str), "LOD %d\n", i);
6684 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6686 destroyed_total = 0;
6687 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6688 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6691 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6694 SDL_snprintf(str, SDL_arraysize(str), "TOTAL: %d\n", total + root_total);
6696 SDL_snprintf(str, SDL_arraysize(str), "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6698 SDL_snprintf(str, SDL_arraysize(str), "TOTAL destroyed faces %d\n\n", destroyed_total);
6701 cfputs("------------------------------------------------------------------------\n\n", out);
6705 if(counted >= MAX_POLYGON_MODELS - 5){
6718 game_spew_pof_info();
6721 static bool game_loop()
6723 if ( popup_active() ) {
6730 if (gameseq_process_events() == GS_STATE_QUIT_GAME) {
6737 #ifdef __EMSCRIPTEN__
6739 void game_loop_caller()
6741 // keep looping through until the persistent storage has sync'd
6742 if (emscripten_run_script_int("Module.sync_in_progress") == 1) {
6746 if ( !game_loop() ) {
6747 emscripten_cancel_main_loop();
6754 int game_main(const char *szCmdLine)
6756 // Find out how much RAM is on this machine
6757 #ifdef __EMSCRIPTEN__
6758 Freespace_total_ram = EM_ASM_INT(return TOTAL_MEMORY) / (1024 * 1024);
6760 Freespace_total_ram = SDL_GetSystemRAM();
6763 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6767 if (!vm_init(24*1024*1024)) {
6768 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough Memory", 199), XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), NULL);
6772 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6774 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough Memory", 199), XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), NULL);
6783 windebug_memwatch_init();
6791 mprintf(("Platform: %s\n", SDL_GetPlatform()));
6792 mprintf(("CPU: %d %s\n", SDL_GetCPUCount(), (SDL_GetCPUCount() == 1) ? "core" : "cores"));
6793 mprintf(("Memory: %dMB\n", Freespace_total_ram));
6794 mprintf(("Build: %d-bit, %s-endian\n", sizeof(void*) * 8, (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? "little" : "big"));
6797 mprintf(("Build ID: %s~%s:%s", GIT_COMMIT_DATE, GIT_BRANCH, GIT_COMMIT_HASH));
6799 mprintf((" (%s)", GIT_TAG));
6804 parse_cmdline(szCmdLine);
6806 mprintf(("--------------------------------------------------------------------------------\n"));
6808 #ifdef STANDALONE_ONLY_BUILD
6810 nprintf(("Network", "Standalone running"));
6813 nprintf(("Network", "Standalone running"));
6820 // maybe spew pof stuff
6821 if(Cmdline_spew_pof_info){
6822 game_spew_pof_info();
6827 // non-demo, non-standalone, play the intro movie
6829 if ( !Is_standalone ) {
6831 // release -- movies always play
6834 // in RELEASE_REAL builds make the user stick in CD2 if there are no pilots on disk so that we guarantee he plays the movie
6835 movie_play( NOX("intro.mve") );
6837 // debug version, movie will only play with -showmovies
6838 #elif !defined(NDEBUG)
6840 movie_play( NOX("intro.mve") );
6843 if ( Cmdline_show_movies )
6844 movie_play( NOX("intro.mve") );
6853 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6855 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6858 #ifdef __EMSCRIPTEN__
6859 emscripten_set_main_loop(game_loop_caller, 0, 1);
6861 while ( game_loop() ) { /* nothing */ }
6868 // launcher the fslauncher program on exit
6869 void game_launch_launcher_on_exit()
6877 // This function is called when FreeSpace terminates normally.
6879 void game_shutdown(void)
6881 // don't ever flip a page on the standalone!
6882 if(!(Game_mode & GM_STANDALONE_SERVER)){
6888 // if the player has left the "player select" screen and quit the game without actually choosing
6889 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6890 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6894 // load up common multiplayer icons
6895 multi_unload_common_icons();
6897 shockwave_close(); // release any memory used by shockwave system
6898 fireball_close(); // free fireball system
6899 ship_close(); // free any memory that was allocated for the ships
6900 weapon_close(); // free any memory that was allocated for the weapons
6901 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6902 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6903 bm_unload_all(); // free bitmaps
6904 mission_campaign_close(); // close out the campaign stuff
6905 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
6906 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6908 #ifdef MULTI_USE_LAG
6912 // the menu close functions will unload the bitmaps if they were displayed during the game
6913 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6916 context_help_close(); // close out help system
6917 training_menu_close();
6918 lcl_close(); // be sure localization is closed out
6921 // free left-over memory from parsed tables
6922 cutscene_tbl_close();
6924 scoring_tbl_close();
6925 player_tips_close();
6927 extern void joy_close();
6930 audiostream_close();
6932 event_music_close();
6936 // HACKITY HACK HACK
6937 // if this flag is set, we should be firing up the launcher when exiting freespace
6938 extern int Multi_update_fireup_launcher_on_exit;
6939 if(Multi_update_fireup_launcher_on_exit){
6940 game_launch_launcher_on_exit();
6943 #ifdef __EMSCRIPTEN__
6944 // sync files to persistent storage
6946 if (Module['onShutdown']) {
6947 Module['onShutdown']();
6953 // game_stop_looped_sounds()
6955 // This function will call the appropriate stop looped sound functions for those
6956 // modules which use looping sounds. It is not enough just to stop a looping sound
6957 // at the DirectSound level, the game is keeping track of looping sounds, and this
6958 // function is used to inform the game that looping sounds are being halted.
6960 void game_stop_looped_sounds()
6962 hud_stop_looped_locking_sounds();
6963 hud_stop_looped_engine_sounds();
6964 afterburner_stop_sounds();
6965 player_stop_looped_sounds();
6966 obj_snd_stop_all(); // stop all object-linked persistant sounds
6967 game_stop_subspace_ambient_sound();
6968 snd_stop(Radar_static_looping);
6969 Radar_static_looping = -1;
6970 snd_stop(Target_static_looping);
6971 shipfx_stop_engine_wash_sound();
6972 Target_static_looping = -1;
6975 //////////////////////////////////////////////////////////////////////////
6977 // Code for supporting an animating mouse pointer
6980 //////////////////////////////////////////////////////////////////////////
6982 typedef struct animating_obj
6991 static animating_obj Animating_mouse;
6993 // ----------------------------------------------------------------------------
6994 // init_animating_pointer()
6996 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6997 // gets properly initialized
6999 void init_animating_pointer()
7001 Animating_mouse.first_frame = -1;
7002 Animating_mouse.num_frames = 0;
7003 Animating_mouse.current_frame = -1;
7004 Animating_mouse.time = 0.0f;
7005 Animating_mouse.elapsed_time = 0.0f;
7008 // ----------------------------------------------------------------------------
7009 // load_animating_pointer()
7011 // Called at game init to load in the frames for the animating mouse pointer
7013 // input: filename => filename of animation file that holds the animation
7015 void load_animating_pointer(const char *filename, int dx, int dy)
7020 init_animating_pointer();
7022 am = &Animating_mouse;
7023 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7024 if ( am->first_frame == -1 )
7025 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7026 am->current_frame = 0;
7027 am->time = am->num_frames / i2fl(fps);
7030 // ----------------------------------------------------------------------------
7031 // unload_animating_pointer()
7033 // Called at game shutdown to free the memory used to store the animation frames
7035 void unload_animating_pointer()
7040 am = &Animating_mouse;
7041 for ( i = 0; i < am->num_frames; i++ ) {
7042 SDL_assert( (am->first_frame+i) >= 0 );
7043 bm_release(am->first_frame + i);
7046 am->first_frame = -1;
7048 am->current_frame = -1;
7051 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7052 void game_render_mouse(float frametime)
7057 // if animating cursor exists, play the next frame
7058 am = &Animating_mouse;
7059 if ( am->first_frame != -1 ) {
7060 mouse_get_pos(&mx, &my);
7061 am->elapsed_time += frametime;
7062 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7063 if ( am->current_frame >= am->num_frames ) {
7064 am->current_frame = 0;
7065 am->elapsed_time = 0.0f;
7067 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7071 // ----------------------------------------------------------------------------
7072 // game_maybe_draw_mouse()
7074 // determines whether to draw the mouse pointer at all, and what frame of
7075 // animation to use if the mouse is animating
7077 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7079 // input: frametime => elapsed frame time in seconds since last call
7081 void game_maybe_draw_mouse(float frametime)
7085 game_state = gameseq_get_state();
7087 switch ( game_state ) {
7088 case GS_STATE_GAME_PAUSED:
7089 // case GS_STATE_MULTI_PAUSED:
7090 case GS_STATE_GAME_PLAY:
7091 case GS_STATE_DEATH_DIED:
7092 case GS_STATE_DEATH_BLEW_UP:
7093 if ( popup_active() || popupdead_is_active() ) {
7105 if ( !Mouse_hidden )
7106 game_render_mouse(frametime);
7110 void game_do_training_checks()
7114 waypoint_list *wplp;
7116 if (Training_context & TRAINING_CONTEXT_SPEED) {
7117 s = (int) Player_obj->phys_info.fspeed;
7118 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7119 if (!Training_context_speed_set) {
7120 Training_context_speed_set = 1;
7121 Training_context_speed_timestamp = timestamp();
7125 Training_context_speed_set = 0;
7128 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7129 wplp = &Waypoint_lists[Training_context_path];
7130 if (wplp->count > Training_context_goal_waypoint) {
7131 i = Training_context_goal_waypoint;
7133 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7134 if (d <= Training_context_distance) {
7135 Training_context_at_waypoint = i;
7136 if (Training_context_goal_waypoint == i) {
7137 Training_context_goal_waypoint++;
7138 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7145 if (i == wplp->count)
7148 } while (i != Training_context_goal_waypoint);
7152 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7153 Players_target = Player_ai->target_objnum;
7154 Players_targeted_subsys = Player_ai->targeted_subsys;
7155 Players_target_timestamp = timestamp();
7159 /////////// Following is for event debug view screen
7163 #define EVENT_DEBUG_MAX 5000
7164 #define EVENT_DEBUG_EVENT 0x8000
7166 int Event_debug_index[EVENT_DEBUG_MAX];
7169 void game_add_event_debug_index(int n, int indent)
7171 if (ED_count < EVENT_DEBUG_MAX)
7172 Event_debug_index[ED_count++] = n | (indent << 16);
7175 void game_add_event_debug_sexp(int n, int indent)
7180 if (Sexp_nodes[n].first >= 0) {
7181 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7182 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7186 game_add_event_debug_index(n, indent);
7187 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7188 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7190 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7193 void game_event_debug_init()
7198 for (e=0; e<Num_mission_events; e++) {
7199 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7200 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7204 void game_show_event_debug(float frametime)
7208 int font_height, font_width;
7210 static int scroll_offset = 0;
7212 k = game_check_key();
7218 if (scroll_offset < 0)
7228 scroll_offset -= 20;
7229 if (scroll_offset < 0)
7234 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7238 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7244 gr_set_color_fast(&Color_bright);
7246 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7248 gr_set_color_fast(&Color_normal);
7250 gr_get_string_size(&font_width, &font_height, NOX("test"));
7251 y_max = gr_screen.max_h - font_height - 5;
7255 while (k < ED_count) {
7256 if (y_index > y_max)
7259 z = Event_debug_index[k];
7260 if (z & EVENT_DEBUG_EVENT) {
7262 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7263 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7264 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7265 Mission_events[z].repeat_count, Mission_events[z].interval);
7273 SDL_strlcat(buf, Sexp_nodes[z & 0x7fff].text, SDL_arraysize(buf));
7274 switch (Sexp_nodes[z & 0x7fff].value) {
7276 SDL_strlcat(buf, NOX(" (True)"), SDL_arraysize(buf));
7280 SDL_strlcat(buf, NOX(" (False)"), SDL_arraysize(buf));
7283 case SEXP_KNOWN_TRUE:
7284 SDL_strlcat(buf, NOX(" (Always true)"), SDL_arraysize(buf));
7287 case SEXP_KNOWN_FALSE:
7288 SDL_strlcat(buf, NOX(" (Always false)"), SDL_arraysize(buf));
7291 case SEXP_CANT_EVAL:
7292 SDL_strlcat(buf, NOX(" (Can't eval)"), SDL_arraysize(buf));
7296 case SEXP_NAN_FOREVER:
7297 SDL_strlcat(buf, NOX(" (Not a number)"), SDL_arraysize(buf));
7302 gr_printf(10, y_index, buf);
7303 y_index += font_height;
7316 int Tmap_num_too_big = 0;
7317 int Num_models_needing_splitting = 0;
7319 void Time_model( int modelnum )
7321 // mprintf(( "Timing ship '%s'\n", si->name ));
7323 vector eye_pos, model_pos;
7324 matrix eye_orient, model_orient;
7326 polymodel *pm = model_get( modelnum );
7328 int l = strlen(pm->filename);
7330 if ( (l == '/') || (l=='\\') || (l==':')) {
7336 char *pof_file = &pm->filename[l];
7338 int model_needs_splitting = 0;
7340 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7342 for (i=0; i<pm->n_textures; i++ ) {
7343 char filename[1024];
7346 int bmp_num = pm->original_textures[i];
7347 if ( bmp_num > -1 ) {
7348 bm_get_palette(pm->original_textures[i], pal, filename, SDL_arraysize(filename) );
7350 bm_get_info( pm->original_textures[i],&w, &h );
7353 if ( (w > 512) || (h > 512) ) {
7354 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7356 model_needs_splitting++;
7359 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7363 if ( model_needs_splitting ) {
7364 Num_models_needing_splitting++;
7366 eye_orient = model_orient = vmd_identity_matrix;
7367 eye_pos = model_pos = vmd_zero_vector;
7369 eye_pos.xyz.z = -pm->rad*2.0f;
7371 vector eye_to_model;
7373 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7374 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7376 fix t1 = timer_get_fixed_seconds();
7379 ta.p = ta.b = ta.h = 0.0f;
7382 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7384 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7386 modelstats_num_polys = modelstats_num_verts = 0;
7388 while( ta.h < PI2 ) {
7391 vm_angles_2_matrix(&m1, &ta );
7392 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7399 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7401 model_clear_instance( modelnum );
7402 model_set_detail_level(0); // use highest detail level
7403 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7411 int k = key_inkey();
7412 if ( k == SDLK_ESCAPE ) {
7417 fix t2 = timer_get_fixed_seconds();
7419 if (framecount < 1) {
7423 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7424 //bitmaps_used_this_frame /= framecount;
7426 modelstats_num_polys /= framecount;
7427 modelstats_num_verts /= framecount;
7429 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7430 fprintf( Time_fp, "\"%s\"\t%.0f\t%d\t%d\t%d\n", pof_file, i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts );
7432 // fprintf( Time_fp, "%.0f\t%d\t%d\t%d\n", i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts );
7438 int Time_models = 0;
7439 DCF_BOOL( time_models, Time_models );
7441 void Do_model_timings_test()
7445 if ( !Time_models ) return;
7447 mprintf(( "Timing models!\n" ));
7451 ubyte model_used[MAX_POLYGON_MODELS];
7452 int model_id[MAX_POLYGON_MODELS];
7453 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7458 for (i=0; i<Num_ship_types; i++ ) {
7459 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7461 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7462 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7465 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7466 if ( !Texture_fp ) return;
7468 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7469 if ( !Time_fp ) return;
7471 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7472 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7474 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7475 if ( model_used[i] ) {
7476 Time_model( model_id[i] );
7480 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7481 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7490 // Call this function when you want to inform the player that a feature is not
7491 // enabled in the DEMO version of FreSpace
7492 void game_feature_not_in_demo_popup()
7494 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7497 // format the specified time (fixed point) into a nice string
7498 void game_format_time(fix m_time, char *time_str, const int time_str_len)
7501 int hours,minutes,seconds;
7503 mtime = f2fl(m_time);
7505 // get the hours, minutes and seconds
7506 hours = (int)(mtime / 3600.0f);
7508 mtime -= (3600.0f * (float)hours);
7510 seconds = (int)mtime%60;
7511 minutes = (int)mtime/60;
7514 SDL_snprintf(time_str, time_str_len, "%d:%02d:%02d", hours, minutes, seconds);
7516 SDL_snprintf(time_str, time_str_len, "%d:%02d", minutes, seconds);
7520 // Stuff version string in *str.
7521 void get_version_string(char *str, const int str_len)
7525 SDL_snprintf(str, str_len, "Dv%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7526 #if !defined(NDEBUG) && defined(GIT_INFO)
7527 SDL_strlcat(str, "~" GIT_COMMIT_HASH, str_len);
7532 if ( FS_VERSION_BUILD == 0 ) {
7533 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7535 SDL_snprintf(str, str_len, "v%d.%02d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7538 #if !defined(NDEBUG) && defined(GIT_INFO)
7539 SDL_strlcat(str, "~" GIT_COMMIT_HASH, str_len);
7542 #if defined (FS2_DEMO)
7543 SDL_strlcat(str, " D", str_len);
7544 #elif defined (OEM_BUILD)
7545 SDL_strlcat(str, " (OEM)", str_len);
7551 char myname[_MAX_PATH];
7552 int namelen, major, minor, build, waste;
7553 unsigned int buf_size;
7559 // Find my EXE file name
7560 hMod = GetModuleHandle(NULL);
7561 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7563 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7564 infop = (char *)malloc(version_size);
7565 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7567 // get the product version
7568 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7569 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7571 sprintf(str,"Dv%d.%02d",major, minor);
7573 sprintf(str,"v%d.%02d",major, minor);
7578 void get_version_string_short(char *str, const int str_len)
7580 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7583 // ----------------------------------------------------------------
7585 // OEM UPSELL SCREENS BEGIN
7587 // ----------------------------------------------------------------
7588 #if defined(OEM_BUILD)
7590 #define NUM_OEM_UPSELL_SCREENS 3
7591 #define OEM_UPSELL_SCREEN_DELAY 10000
7593 static int Oem_upsell_bitmaps_loaded = 0;
7594 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7595 static int Oem_upsell_screen_number = 0;
7596 static int Oem_upsell_show_next_bitmap_time;
7599 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7612 static int Oem_normal_cursor = -1;
7613 static int Oem_web_cursor = -1;
7614 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7615 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7617 void oem_upsell_next_screen()
7619 Oem_upsell_screen_number++;
7620 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7621 // extra long delay, mouse shown on last upsell
7622 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7626 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7630 void oem_upsell_load_bitmaps()
7634 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7635 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7639 void oem_upsell_unload_bitmaps()
7643 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7644 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7645 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7650 Oem_upsell_bitmaps_loaded = 0;
7653 // clickable hotspot on 3rd OEM upsell screen
7654 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7656 28, 350, 287, 96 // x, y, w, h
7659 45, 561, 460, 152 // x, y, w, h
7663 void oem_upsell_show_screens()
7665 int current_time, k;
7668 if ( !Oem_upsell_bitmaps_loaded ) {
7669 oem_upsell_load_bitmaps();
7670 Oem_upsell_bitmaps_loaded = 1;
7673 // may use upsell screens more than once
7674 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7675 Oem_upsell_screen_number = 0;
7681 int nframes; // used to pass, not really needed (should be 1)
7682 Oem_normal_cursor = gr_get_cursor_bitmap();
7683 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7684 SDL_assert(Oem_web_cursor >= 0);
7685 if (Oem_web_cursor < 0) {
7686 Oem_web_cursor = Oem_normal_cursor;
7691 //oem_reset_trailer_timer();
7693 current_time = timer_get_milliseconds();
7698 // advance screen on keypress or timeout
7699 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7700 oem_upsell_next_screen();
7703 // check if we are done
7704 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7705 Oem_upsell_screen_number--;
7708 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7713 // show me the upsell
7714 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7715 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7719 // if this is the 3rd upsell, make it clickable, d00d
7720 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7722 int button_state = mouse_get_pos(&mx, &my);
7723 if ( (mx >= Oem_upsell3_button_coords[gr_screen.res][0]) && (mx <= Oem_upsell3_button_coords[gr_screen.res][0] + Oem_upsell3_button_coords[gr_screen.res][2])
7724 && (my >= Oem_upsell3_button_coords[gr_screen.res][1]) && (my <= Oem_upsell3_button_coords[gr_screen.res][1] + Oem_upsell3_button_coords[gr_screen.res][3]) )
7727 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7730 if (button_state & MOUSE_LEFT_BUTTON) {
7732 multi_pxo_url(OEM_UPSELL_URL);
7736 // switch cursor back to normal one
7737 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7742 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7752 oem_upsell_unload_bitmaps();
7754 // switch cursor back to normal one
7755 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7759 #endif // defined(OEM_BUILD)
7760 // ----------------------------------------------------------------
7762 // OEM UPSELL SCREENS END
7764 // ----------------------------------------------------------------
7768 // ----------------------------------------------------------------
7770 // DEMO UPSELL SCREENS BEGIN
7772 // ----------------------------------------------------------------
7774 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7777 #define NUM_DEMO_UPSELL_SCREENS 4
7778 #define DEMO_UPSELL_SCREEN_DELAY 15000
7780 #define NUM_DEMO_UPSELL_SCREENS 2
7781 #define DEMO_UPSELL_SCREEN_DELAY 3000
7785 static int Demo_upsell_bitmaps_loaded = 0;
7786 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7787 static int Demo_upsell_screen_number = 0;
7788 static int Demo_upsell_show_next_bitmap_time;
7789 static int Demo_upsell_quit_on_done = 0;
7790 static int Demo_upsell_end_timer = 0;
7793 static const char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7819 void demo_upsell_next_screen()
7821 Demo_upsell_screen_number++;
7822 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7823 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7825 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7829 void demo_upsell_load_bitmaps()
7833 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7834 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7838 void demo_upsell_unload_bitmaps()
7842 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7843 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7844 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7849 Demo_upsell_bitmaps_loaded = 0;
7852 void demo_upsell_init(int end_of_demo)
7854 if ( !Demo_upsell_bitmaps_loaded ) {
7855 demo_upsell_load_bitmaps();
7856 Demo_upsell_bitmaps_loaded = 1;
7859 Demo_upsell_end_timer = 0;
7860 Demo_upsell_quit_on_done = !end_of_demo;
7862 // may use upsell screens more than once
7863 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7864 Demo_upsell_screen_number = 0;
7870 void demo_upsell_close()
7873 demo_upsell_unload_bitmaps();
7876 void demo_upsell_do()
7880 demo_reset_trailer_timer();
7884 if ( !Demo_upsell_end_timer ) {
7885 int k = key_inkey();
7888 if ( timer_get_milliseconds() > Demo_upsell_show_next_bitmap_time ) {
7889 demo_upsell_next_screen();
7895 demo_upsell_next_screen();
7898 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7899 Demo_upsell_screen_number--;
7902 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7908 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7909 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7913 if ( Demo_upsell_end_timer && (timer_get_milliseconds() > Demo_upsell_end_timer) ) {
7914 gameseq_post_event(GS_EVENT_QUIT_GAME);
7916 if (Demo_upsell_quit_on_done) {
7918 Demo_upsell_end_timer = timer_get_milliseconds() + 300;
7920 gameseq_post_event(GS_EVENT_MAIN_MENU);
7929 // ----------------------------------------------------------------
7931 // DEMO UPSELL SCREENS END
7933 // ----------------------------------------------------------------
7936 // ----------------------------------------------------------------
7938 // Subspace Ambient Sound START
7940 // ----------------------------------------------------------------
7942 static int Subspace_ambient_left_channel = -1;
7943 static int Subspace_ambient_right_channel = -1;
7946 void game_start_subspace_ambient_sound()
7948 if ( Subspace_ambient_left_channel < 0 ) {
7949 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7952 if ( Subspace_ambient_right_channel < 0 ) {
7953 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7957 void game_stop_subspace_ambient_sound()
7959 if ( Subspace_ambient_left_channel >= 0 ) {
7960 snd_stop(Subspace_ambient_left_channel);
7961 Subspace_ambient_left_channel = -1;
7964 if ( Subspace_ambient_right_channel >= 0 ) {
7965 snd_stop(Subspace_ambient_right_channel);
7966 Subspace_ambient_right_channel = -1;
7970 // ----------------------------------------------------------------
7972 // Subspace Ambient Sound END
7974 // ----------------------------------------------------------------
7976 // ----------------------------------------------------------------
7978 // Language Autodetection stuff
7981 // this layout order must match Lcl_languages in localize.cpp in order for the
7982 // correct language to be detected
7983 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
7985 1366105450, // English
7987 589986744, // English
7989 -1132430286, // German
7991 -1131728960, // Polish
7994 // default setting is "-1" to use config file with English as fall back
7995 // DO NOT change the default setting here or something uncouth might happen
7996 // in the localization code
8002 // try and open the file to verify
8003 CFILE *detect = cfopen("font01.vf", "rb");
8005 // will use default setting if something went wrong
8010 // get the long checksum of the file
8012 cfseek(detect, 0, SEEK_SET);
8013 cf_chksum_long(detect, &file_checksum);
8017 // now compare the checksum/filesize against known #'s
8018 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8019 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8024 // notify if a match was not found, include detected checksum
8025 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8026 printf("Using default language...\n\n");
8032 // End Auto Lang stuff
8034 // ----------------------------------------------------------------
8036 // ----------------------------------------------------------------
8037 // SHIPS TBL VERIFICATION STUFF
8040 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8041 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8042 #define NUM_SHIPS_TBL_CHECKSUMS 3
8044 #define NUM_SHIPS_TBL_CHECKSUMS 1
8047 #if defined(FS2_DEMO)
8048 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8049 1696074201, // FS2 demo
8051 #elif defined(FS1_DEMO)
8052 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8053 1603375034, // FS1 DEMO
8055 #elif defined(MAKE_FS1)
8056 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8057 -129679197, // FS1 Full 1.06 (US)
8058 7762567, // FS1 SilentThreat
8059 1555372475 // FS1 Full 1.06 (German)
8063 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8064 -463907578, // US - beta 1
8065 1696074201, // FS2 demo
8068 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8069 // -1022810006, // 1.0 FULL
8070 -1254285366 // 1.2 FULL (German)
8074 void verify_ships_tbl()
8078 Game_ships_tbl_valid = 1;
8084 // detect if the packfile exists
8085 CFILE *detect = cfopen("ships.tbl", "rb");
8086 Game_ships_tbl_valid = 0;
8090 Game_ships_tbl_valid = 0;
8094 // get the long checksum of the file
8096 cfseek(detect, 0, SEEK_SET);
8097 cf_chksum_long(detect, &file_checksum);
8101 // now compare the checksum/filesize against known #'s
8102 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8103 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8104 Game_ships_tbl_valid = 1;
8111 DCF(shipspew, "display the checksum for the current ships.tbl")
8114 CFILE *detect = cfopen("ships.tbl", "rb");
8115 // get the long checksum of the file
8117 cfseek(detect, 0, SEEK_SET);
8118 cf_chksum_long(detect, &file_checksum);
8121 dc_printf("%d", file_checksum);
8124 // ----------------------------------------------------------------
8125 // WEAPONS TBL VERIFICATION STUFF
8128 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8129 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8130 #define NUM_WEAPONS_TBL_CHECKSUMS 3
8132 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8135 #if defined(FS2_DEMO)
8136 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8137 -266420030, // demo 1
8139 #elif defined(FS1_DEMO)
8140 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8141 -1246928725, // FS1 DEMO
8143 #elif defined(MAKE_FS1)
8144 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8145 -834598107, // FS1 1.06 Full (US)
8146 -1652231417, // FS1 SilentThreat
8147 720209793 // FS1 1.06 Full (German)
8151 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8152 141718090, // US - beta 1
8153 -266420030, // demo 1
8156 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8157 // 399297860, // 1.0 FULL
8158 -553984927 // 1.2 FULL (german)
8162 void verify_weapons_tbl()
8166 Game_weapons_tbl_valid = 1;
8172 // detect if the packfile exists
8173 CFILE *detect = cfopen("weapons.tbl", "rb");
8174 Game_weapons_tbl_valid = 0;
8178 Game_weapons_tbl_valid = 0;
8182 // get the long checksum of the file
8184 cfseek(detect, 0, SEEK_SET);
8185 cf_chksum_long(detect, &file_checksum);
8189 // now compare the checksum/filesize against known #'s
8190 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8191 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8192 Game_weapons_tbl_valid = 1;
8199 DCF(wepspew, "display the checksum for the current weapons.tbl")
8202 CFILE *detect = cfopen("weapons.tbl", "rb");
8203 // get the long checksum of the file
8205 cfseek(detect, 0, SEEK_SET);
8206 cf_chksum_long(detect, &file_checksum);
8209 dc_printf("%d", file_checksum);
8212 // if the game is running using hacked data
8213 int game_hacked_data()
8216 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8224 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8226 void display_title_screen()
8229 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8230 if (title_bitmap == -1) {
8235 gr_set_bitmap(title_bitmap);
8243 // give it some time on screen
8244 #ifdef __EMSCRIPTEN__
8245 //emscripten_sleep(1000);
8250 bm_unload(title_bitmap);
8252 #endif // FS2_DEMO || OEM_BUILD
8254 // return true if the game is running with "low memory", which is less than 48MB
8255 bool game_using_low_mem()
8257 if (Use_low_mem == 0) {