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 int Game_no_clear = 0;
735 int Pofview_running = 0;
736 int Nebedit_running = 0;
737 int Fonttool_running = 0;
739 typedef struct big_expl_flash {
740 float max_flash_intensity; // max intensity
741 float cur_flash_intensity; // cur intensity
742 int flash_start; // start time
745 #define FRAME_FILTER 16
747 #define DEFAULT_SKILL_LEVEL 1
748 int Game_skill_level = DEFAULT_SKILL_LEVEL;
750 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
751 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
753 #define EXE_FNAME ("fs2.exe")
754 #define LAUNCHER_FNAME ("freespace2.exe")
757 // JAS: Code for warphole camera.
758 // Needs to be cleaned up.
759 vector Camera_pos = ZERO_VECTOR;
760 vector Camera_velocity = ZERO_VECTOR;
761 vector Camera_desired_velocity = ZERO_VECTOR;
762 matrix Camera_orient = IDENTITY_MATRIX;
763 float Camera_damping = 1.0f;
764 float Camera_time = 0.0f;
765 float Warpout_time = 0.0f;
766 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
767 int Warpout_sound = -1;
769 int Use_joy_mouse = 0;
770 int Use_palette_flash = 1;
771 int Show_area_effect = 0;
772 object *Last_view_target = NULL;
774 int dogfight_blown = 0;
777 float frametimes[FRAME_FILTER];
778 float frametotal = 0.0f;
782 int Show_framerate = 0;
784 int Show_framerate = 1;
787 int Framerate_cap = 120;
790 int Show_target_debug_info = 0;
791 int Show_target_weapons = 0;
795 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
798 int Debug_octant = -1;
800 fix Game_time_compression = F1_0;
802 // if the ships.tbl the player has is valid
803 int Game_ships_tbl_valid = 0;
805 // if the weapons.tbl the player has is valid
806 int Game_weapons_tbl_valid = 0;
810 extern int Player_attacking_enabled;
814 int Pre_player_entry;
816 int Fred_running = 0;
817 char Game_current_mission_filename[MAX_FILENAME_LEN];
818 int game_single_step = 0;
819 int last_single_step=0;
821 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
822 extern int MSG_WINDOW_Y_START;
823 extern int MSG_WINDOW_HEIGHT;
825 int game_zbuffer = 1;
826 //static int Game_music_paused;
827 static int Game_paused;
831 #define EXPIRE_BAD_CHECKSUM 1
832 #define EXPIRE_BAD_TIME 2
834 extern void ssm_init();
835 extern void ssm_level_init();
836 extern void ssm_process();
838 // static variable to contain the time this version was built
839 // commented out for now until
840 // I figure out how to get the username into the file
841 //static char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
843 // defines and variables used for dumping frame for making trailers.
845 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
846 int Debug_dump_trigger = 0;
847 int Debug_dump_frame_count;
848 int Debug_dump_frame_num = 0;
849 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
852 // amount of time to wait after the player has died before we display the death died popup
853 #define PLAYER_DIED_POPUP_WAIT 2500
854 int Player_died_popup_wait = -1;
855 time_t Player_multi_died_check = -1;
857 // builtin mission list stuff
859 int Game_builtin_mission_count = 6;
860 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
861 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
862 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
863 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
864 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
865 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
866 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
868 #elif defined(FS1_DEMO)
869 int Game_builtin_mission_count = 5;
870 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
871 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
872 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
873 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
874 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
875 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
877 #elif defined(PD_BUILD)
878 int Game_builtin_mission_count = 4;
879 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
880 { "sm1-01.fs2", (FSB_FROM_VOLITION) },
881 { "sm1-05.fs2", (FSB_FROM_VOLITION) },
882 { "sm1-01", (FSB_FROM_VOLITION) },
883 { "sm1-05", (FSB_FROM_VOLITION) },
885 #elif defined(MULTIPLAYER_BETA)
886 int Game_builtin_mission_count = 17;
887 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
889 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
890 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
891 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
892 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
893 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
894 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
895 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
896 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
897 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
898 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
899 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
900 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
901 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
902 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
903 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
904 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
905 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
907 #elif defined(OEM_BUILD)
908 int Game_builtin_mission_count = 17;
909 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
910 // oem version - act 1 only
911 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
914 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
915 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
916 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
917 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
918 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
919 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
920 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
921 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
922 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
923 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
924 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
925 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
926 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
927 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
928 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
929 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) }
931 #elif defined(MAKE_FS1)
932 int Game_builtin_mission_count = 125;
933 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
934 // single player campaign
935 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
938 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
939 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
940 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
941 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
942 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
943 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
944 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
945 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
946 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
947 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
950 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
951 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
952 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
953 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
954 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
955 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
956 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
957 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
958 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
959 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
962 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
963 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
964 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
965 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
966 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
967 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
968 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
969 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
970 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
973 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
974 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
975 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
978 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
979 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
980 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
981 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
982 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
985 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
986 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
988 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
989 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
990 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
991 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
992 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
993 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
994 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
995 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
996 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
997 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
998 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
999 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1000 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1001 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1002 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1003 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1004 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1005 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1006 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1008 // SilentThreat missions
1009 // Main SilentThreat campaign
1010 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE) },
1012 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1013 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1014 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1015 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1016 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1017 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1018 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1019 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1020 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1021 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1022 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1023 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1025 // SilentThreat Part 1 - multi-coop
1026 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1028 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1029 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1030 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1032 // SilentThreat Part 2 - multi-coop
1033 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1035 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1036 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1037 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1039 // SilentThreat Part 3 - multi-coop
1040 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1042 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1043 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1044 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1046 // SilentThreat Part 4 - multi-coop
1047 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1049 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1050 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1051 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1053 // multiplayer missions
1054 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1055 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1056 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1057 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1058 // user supplied missions
1059 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1060 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1061 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1062 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1063 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1064 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1065 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1066 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1067 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1068 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1069 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1070 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1071 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1072 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1073 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1074 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1075 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1076 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1077 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1078 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1079 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1080 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1081 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1082 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1083 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1084 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1085 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1086 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1087 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1088 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1089 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1090 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1093 int Game_builtin_mission_count = 92;
1094 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1095 // single player campaign
1096 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
1099 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1100 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1101 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1102 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1103 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1104 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1105 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1106 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1107 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1108 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1109 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1110 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1111 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1112 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1113 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1114 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1115 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1116 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1117 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1120 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1121 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1122 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1123 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1124 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1125 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1126 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1127 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1128 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1129 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1132 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1133 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1134 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1135 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1136 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1137 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1138 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1139 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1140 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1141 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1142 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1143 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1145 // multiplayer missions
1148 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1149 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1150 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1153 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1154 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1155 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1156 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1159 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1160 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1161 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1162 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1163 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1164 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1165 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1166 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1167 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1168 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1169 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1170 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1171 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1172 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1173 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1174 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1175 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1176 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1177 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1178 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1179 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1180 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1181 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1182 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1183 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1184 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1185 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1186 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1189 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1190 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1191 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1192 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1193 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1194 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1195 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1196 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1197 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1198 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1201 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1202 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1203 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1204 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1205 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1210 // Internal function prototypes
1211 void game_maybe_draw_mouse(float frametime);
1212 void init_animating_pointer();
1213 void load_animating_pointer(const char *filename, int dx, int dy);
1214 void unload_animating_pointer();
1215 void game_do_training_checks();
1216 void game_shutdown(void);
1217 void game_show_event_debug(float frametime);
1218 void game_event_debug_init();
1220 void demo_upsell_show_screens();
1221 void game_start_subspace_ambient_sound();
1222 void game_stop_subspace_ambient_sound();
1223 void verify_ships_tbl();
1224 void verify_weapons_tbl();
1225 void display_title_screen();
1227 // loading background filenames
1228 static const char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1229 "LoadingBG", // GR_640
1230 "2_LoadingBG" // GR_1024
1234 static const char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1235 "Loading.ani", // GR_640
1236 "2_Loading.ani" // GR_1024
1239 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1240 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1248 #elif defined(OEM_BUILD)
1249 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1258 // How much RAM is on this machine. Set in WinMain
1259 static int Freespace_total_ram = 0;
1262 float Game_flash_red = 0.0f;
1263 float Game_flash_green = 0.0f;
1264 float Game_flash_blue = 0.0f;
1265 float Sun_spot = 0.0f;
1266 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1268 // game shudder stuff (in ms)
1269 int Game_shudder_time = -1;
1270 int Game_shudder_total = 0;
1271 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1274 sound_env Game_sound_env;
1275 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1276 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1278 int Game_sound_env_update_timestamp;
1280 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1283 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1285 fs_builtin_mission *game_find_builtin_mission(const char *filename)
1289 // look through all existing builtin missions
1290 for(idx=0; idx<Game_builtin_mission_count; idx++){
1291 if(!SDL_strcasecmp(Game_builtin_mission_list[idx].filename, filename)){
1292 return &Game_builtin_mission_list[idx];
1300 int game_get_default_skill_level()
1302 return DEFAULT_SKILL_LEVEL;
1306 void game_flash_reset()
1308 Game_flash_red = 0.0f;
1309 Game_flash_green = 0.0f;
1310 Game_flash_blue = 0.0f;
1312 Big_expl_flash.max_flash_intensity = 0.0f;
1313 Big_expl_flash.cur_flash_intensity = 0.0f;
1314 Big_expl_flash.flash_start = 0;
1317 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1318 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1320 void game_framerate_check_init()
1322 // zero critical time
1323 Gf_critical_time = 0.0f;
1326 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1327 Gf_critical = 15.0f;
1329 Gf_critical = 25.0f;
1333 extern float Framerate;
1334 void game_framerate_check()
1338 // if the current framerate is above the critical level, add frametime
1339 if(Framerate >= Gf_critical){
1340 Gf_critical_time += flFrametime;
1343 if(!Show_framerate){
1347 // display if we're above the critical framerate
1348 if(Framerate < Gf_critical){
1349 gr_set_color_fast(&Color_bright_red);
1350 gr_string(200, y_start, "Framerate warning");
1355 // display our current pct of good frametime
1356 if(f2fl(Missiontime) >= 0.0f){
1357 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1360 gr_set_color_fast(&Color_bright_green);
1362 gr_set_color_fast(&Color_bright_red);
1365 gr_printf(200, y_start, "%d%%", (int)pct);
1370 // Adds a flash effect. These can be positive or negative.
1371 // The range will get capped at around -1 to 1, so stick
1372 // with a range like that.
1373 void game_flash( float r, float g, float b )
1375 Game_flash_red += r;
1376 Game_flash_green += g;
1377 Game_flash_blue += b;
1379 if ( Game_flash_red < -1.0f ) {
1380 Game_flash_red = -1.0f;
1381 } else if ( Game_flash_red > 1.0f ) {
1382 Game_flash_red = 1.0f;
1385 if ( Game_flash_green < -1.0f ) {
1386 Game_flash_green = -1.0f;
1387 } else if ( Game_flash_green > 1.0f ) {
1388 Game_flash_green = 1.0f;
1391 if ( Game_flash_blue < -1.0f ) {
1392 Game_flash_blue = -1.0f;
1393 } else if ( Game_flash_blue > 1.0f ) {
1394 Game_flash_blue = 1.0f;
1399 // Adds a flash for Big Ship explosions
1400 // cap range from 0 to 1
1401 void big_explosion_flash(float flash)
1403 Big_expl_flash.flash_start = timestamp(1);
1407 } else if (flash < 0.0f) {
1411 Big_expl_flash.max_flash_intensity = flash;
1412 Big_expl_flash.cur_flash_intensity = 0.0f;
1415 // Amount to diminish palette towards normal, per second.
1416 #define DIMINISH_RATE 0.75f
1417 #define SUN_DIMINISH_RATE 6.00f
1421 float sn_glare_scale = 1.7f;
1424 dc_get_arg(ARG_FLOAT);
1425 sn_glare_scale = Dc_arg_float;
1428 float Supernova_last_glare = 0.0f;
1429 void game_sunspot_process(float frametime)
1433 float Sun_spot_goal = 0.0f;
1436 sn_stage = supernova_active();
1438 // sunspot differently based on supernova stage
1440 // approaching. player still in control
1443 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1446 light_get_global_dir(&light_dir, 0);
1448 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1451 // scale it some more
1452 dot = dot * (0.5f + (pct * 0.5f));
1455 Sun_spot_goal += (dot * sn_glare_scale);
1458 // draw the sun glow
1459 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1460 // draw the glow for this sun
1461 stars_draw_sun_glow(0);
1464 Supernova_last_glare = Sun_spot_goal;
1467 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1470 Sun_spot_goal = 0.9f;
1471 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1473 if(Sun_spot_goal > 1.0f){
1474 Sun_spot_goal = 1.0f;
1477 Sun_spot_goal *= sn_glare_scale;
1478 Supernova_last_glare = Sun_spot_goal;
1481 // fade to white. display dead popup
1484 Supernova_last_glare += (2.0f * flFrametime);
1485 if(Supernova_last_glare > 2.0f){
1486 Supernova_last_glare = 2.0f;
1489 Sun_spot_goal = Supernova_last_glare;
1496 // check sunspots for all suns
1497 n_lights = light_get_global_count();
1500 for(idx=0; idx<n_lights; idx++){
1501 //(vector *eye_pos, matrix *eye_orient)
1502 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1505 light_get_global_dir(&light_dir, idx);
1507 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1509 Sun_spot_goal += (float)pow(dot,85.0f);
1511 // draw the glow for this sun
1512 stars_draw_sun_glow(idx);
1514 Sun_spot_goal = 0.0f;
1520 Sun_spot_goal = 0.0f;
1524 float dec_amount = frametime*SUN_DIMINISH_RATE;
1526 if ( Sun_spot < Sun_spot_goal ) {
1527 Sun_spot += dec_amount;
1528 if ( Sun_spot > Sun_spot_goal ) {
1529 Sun_spot = Sun_spot_goal;
1531 } else if ( Sun_spot > Sun_spot_goal ) {
1532 Sun_spot -= dec_amount;
1533 if ( Sun_spot < Sun_spot_goal ) {
1534 Sun_spot = Sun_spot_goal;
1540 // Call once a frame to diminish the
1541 // flash effect to 0.
1542 void game_flash_diminish(float frametime)
1544 float dec_amount = frametime*DIMINISH_RATE;
1546 if ( Game_flash_red > 0.0f ) {
1547 Game_flash_red -= dec_amount;
1548 if ( Game_flash_red < 0.0f )
1549 Game_flash_red = 0.0f;
1551 Game_flash_red += dec_amount;
1552 if ( Game_flash_red > 0.0f )
1553 Game_flash_red = 0.0f;
1556 if ( Game_flash_green > 0.0f ) {
1557 Game_flash_green -= dec_amount;
1558 if ( Game_flash_green < 0.0f )
1559 Game_flash_green = 0.0f;
1561 Game_flash_green += dec_amount;
1562 if ( Game_flash_green > 0.0f )
1563 Game_flash_green = 0.0f;
1566 if ( Game_flash_blue > 0.0f ) {
1567 Game_flash_blue -= dec_amount;
1568 if ( Game_flash_blue < 0.0f )
1569 Game_flash_blue = 0.0f;
1571 Game_flash_blue += dec_amount;
1572 if ( Game_flash_blue > 0.0f )
1573 Game_flash_blue = 0.0f;
1576 // update big_explosion_cur_flash
1577 #define TIME_UP 1500
1578 #define TIME_DOWN 2500
1579 int duration = TIME_UP + TIME_DOWN;
1580 int time = timestamp_until(Big_expl_flash.flash_start);
1581 if (time > -duration) {
1583 if (time < TIME_UP) {
1584 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1587 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1591 if ( Use_palette_flash ) {
1593 // static int or=0, og=0, ob=0;
1595 // Change the 200 to change the color range of colors.
1596 r = fl2i( Game_flash_red*128.0f );
1597 g = fl2i( Game_flash_green*128.0f );
1598 b = fl2i( Game_flash_blue*128.0f );
1600 if ( Sun_spot > 0.0f ) {
1601 r += fl2i(Sun_spot*128.0f);
1602 g += fl2i(Sun_spot*128.0f);
1603 b += fl2i(Sun_spot*128.0f);
1606 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1607 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1608 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1609 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1612 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1613 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1614 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1616 if ( (r!=0) || (g!=0) || (b!=0) ) {
1617 gr_flash( r, g, b );
1619 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1630 void game_level_close()
1632 // De-Initialize the game subsystems
1633 event_music_level_close();
1634 game_stop_looped_sounds();
1636 obj_snd_level_close(); // uninit object-linked persistant sounds
1637 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1638 anim_level_close(); // stop and clean up any anim instances
1639 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1640 shockwave_level_close();
1641 fireball_level_close();
1643 mission_event_shutdown();
1644 asteroid_level_close();
1645 flak_level_close(); // unload flak stuff
1646 neb2_level_close(); // shutdown gaseous nebula stuff
1649 mflash_level_close();
1650 mission_brief_common_reset(); // close out parsed briefing/mission stuff
1652 audiostream_unpause_all();
1657 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1658 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1659 void game_level_init(int seed)
1661 // seed the random number generator
1663 // if no seed was passed, seed the generator either from the time value, or from the
1664 // netgame security flags -- ensures that all players in multiplayer game will have the
1665 // same randon number sequence (with static rand functions)
1666 if ( Game_mode & GM_NORMAL ) {
1667 Game_level_seed = (int)time(NULL);
1669 Game_level_seed = Netgame.security;
1672 // mwa 9/17/98 -- maybe this assert isn't needed????
1673 SDL_assert( !(Game_mode & GM_MULTIPLAYER) );
1674 Game_level_seed = seed;
1676 srand( Game_level_seed );
1678 // semirand function needs to get re-initted every time in multiplayer
1679 if ( Game_mode & GM_MULTIPLAYER ){
1685 Key_normal_game = (Game_mode & GM_NORMAL);
1688 Game_shudder_time = -1;
1690 // Initialize the game subsystems
1691 // timestamp_reset(); // Must be inited before everything else
1693 game_reset_time(); // resets time, and resets saved time too
1695 obj_init(); // Must be inited before the other systems
1696 model_free_all(); // Free all existing models
1697 mission_brief_common_init(); // Free all existing briefing/debriefing text
1698 weapon_level_init();
1699 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1701 player_level_init();
1702 shipfx_flash_init(); // Init the ship gun flash system.
1703 game_flash_reset(); // Reset the flash effect
1704 particle_init(); // Reset the particle system
1708 shield_hit_init(); // Initialize system for showing shield hits
1709 radar_mission_init();
1710 mission_init_goals();
1713 obj_snd_level_init(); // init object-linked persistant sounds
1715 shockwave_level_init();
1716 afterburner_level_init();
1717 scoring_level_init( &Player->stats );
1719 asteroid_level_init();
1720 control_config_clear_used_status();
1721 collide_ship_ship_sounds_init();
1723 Pre_player_entry = 1; // Means the player has not yet entered.
1724 Entry_delay_time = 0; // Could get overwritten in mission read.
1725 fireball_preload(); // page in warphole bitmaps
1727 flak_level_init(); // initialize flak - bitmaps, etc
1728 ct_level_init(); // initialize ships contrails, etc
1729 awacs_level_init(); // initialize AWACS
1730 beam_level_init(); // initialize beam weapons
1731 mflash_level_init();
1733 supernova_level_init();
1735 // multiplayer dogfight hack
1738 shipfx_engine_wash_level_init();
1742 Last_view_target = NULL;
1747 // campaign wasn't ended
1748 Campaign_ended_in_mission = 0;
1751 // called when a mission is over -- does server specific stuff.
1752 void freespace_stop_mission()
1755 Game_mode &= ~GM_IN_MISSION;
1758 // called at frame interval to process networking stuff
1759 void game_do_networking()
1761 SDL_assert( Net_player != NULL );
1762 if (!(Game_mode & GM_MULTIPLAYER)){
1766 // see if this player should be reading/writing data. Bit is set when at join
1767 // screen onward until quits back to main menu.
1768 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1772 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1775 multi_pause_do_frame();
1780 // Loads the best palette for this level, based
1781 // on nebula color and hud color. You could just call palette_load_table with
1782 // the appropriate filename, but who wants to do that.
1783 void game_load_palette()
1785 char palette_filename[1024];
1787 // We only use 3 hud colors right now
1789 SDL_assert( HUD_config.main_color >= 0 );
1790 SDL_assert( HUD_config.main_color <= 2 );
1793 SDL_assert( Mission_palette >= 0 );
1794 SDL_assert( Mission_palette <= 98 );
1797 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1798 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), SDL_arraysize(palette_filename) );
1800 SDL_snprintf( palette_filename, SDL_arraysize(palette_filename), NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1803 mprintf(( "Loading palette %s\n", palette_filename ));
1805 palette_load_table(palette_filename);
1807 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), SDL_arraysize(palette_filename) );
1809 mprintf(( "Loading palette %s\n", palette_filename ));
1813 void game_post_level_init()
1815 // Stuff which gets called after mission is loaded. Because player isn't created until
1816 // after mission loads, some things must get initted after the level loads
1818 model_level_post_init();
1821 hud_setup_escort_list();
1822 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1828 game_event_debug_init();
1831 training_mission_init();
1832 asteroid_create_all();
1834 game_framerate_check_init();
1838 // An estimate as to how high the count passed to game_loading_callback will go.
1839 // This is just a guess, it seems to always be about the same. The count is
1840 // proportional to the code being executed, not the time, so this works good
1841 // for a bar, assuming the code does about the same thing each time you
1842 // load a level. You can find this value by looking at the return value
1843 // of game_busy_callback(NULL), which I conveniently print out to the
1844 // debug output window with the '=== ENDING LOAD ==' stuff.
1845 //#define COUNT_ESTIMATE 3706
1846 #define COUNT_ESTIMATE 1111
1848 int Game_loading_callback_inited = 0;
1850 int Game_loading_background = -1;
1851 anim * Game_loading_ani = NULL;
1852 anim_instance *Game_loading_ani_instance;
1853 int Game_loading_frame=-1;
1855 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1857 #if defined(FS1_DEMO)
1859 #elif defined(MAKE_FS1)
1870 // This gets called 10x per second and count is the number of times
1871 // game_busy() has been called since the current callback function
1873 void game_loading_callback(int count)
1875 game_do_networking();
1877 SDL_assert( Game_loading_callback_inited==1 );
1878 SDL_assert( Game_loading_ani != NULL );
1880 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1881 if ( framenum > Game_loading_ani->total_frames-1 ) {
1882 framenum = Game_loading_ani->total_frames-1;
1883 } else if ( framenum < 0 ) {
1888 while ( Game_loading_frame < framenum ) {
1889 Game_loading_frame++;
1890 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1894 if ( cbitmap > -1 ) {
1895 if ( Game_loading_background > -1 ) {
1896 gr_set_bitmap( Game_loading_background, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1900 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1901 gr_set_bitmap( cbitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1902 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1904 bm_release(cbitmap);
1910 void game_loading_callback_init()
1912 SDL_assert( Game_loading_callback_inited==0 );
1914 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1916 common_set_interface_palette("InterfacePalette"); // set the interface palette
1920 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1921 SDL_assert( Game_loading_ani != NULL );
1922 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1923 SDL_assert( Game_loading_ani_instance != NULL );
1924 Game_loading_frame = -1;
1926 Game_loading_callback_inited = 1;
1928 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1933 void game_loading_callback_close()
1935 SDL_assert( Game_loading_callback_inited==1 );
1937 // Make sure bar shows all the way over.
1938 game_loading_callback(COUNT_ESTIMATE);
1941 int real_count = game_busy_callback( NULL );
1943 mprintf(( "=================== ENDING LOAD ================\n" ));
1944 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1945 mprintf(( "================================================\n" ));
1947 game_busy_callback( NULL );
1952 Game_loading_callback_inited = 0;
1954 free_anim_instance(Game_loading_ani_instance);
1955 Game_loading_ani_instance = NULL;
1956 anim_free(Game_loading_ani);
1957 Game_loading_ani = NULL;
1959 bm_release( Game_loading_background );
1960 common_free_interface_palette(); // restore game palette
1961 Game_loading_background = -1;
1963 gr_set_font( FONT1 );
1966 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1968 void game_maybe_update_sound_environment()
1970 // do nothing for now
1973 // Assign the sound environment for the game, based on the current mission
1975 void game_assign_sound_environment()
1978 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1979 Game_sound_env.id = SND_ENV_DRUGGED;
1980 Game_sound_env.volume = 0.800f;
1981 Game_sound_env.damping = 1.188f;
1982 Game_sound_env.decay = 6.392f;
1984 } else if (Num_asteroids > 30) {
1985 Game_sound_env.id = SND_ENV_AUDITORIUM;
1986 Game_sound_env.volume = 0.603f;
1987 Game_sound_env.damping = 0.5f;
1988 Game_sound_env.decay = 4.279f;
1991 Game_sound_env = Game_default_sound_env;
1994 Game_sound_env = Game_default_sound_env;
1997 Game_sound_env_update_timestamp = timestamp(1);
2000 // function which gets called before actually entering the mission. It is broken down into a funciton
2001 // since it will get called in one place from a single player game and from another place for
2002 // a multiplayer game
2003 void freespace_mission_load_stuff()
2005 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2006 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2007 if(!(Game_mode & GM_STANDALONE_SERVER)){
2009 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2011 game_loading_callback_init();
2013 event_music_level_init(); // preloads the first 2 seconds for each event music track
2016 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2019 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2022 ship_assign_sound_all(); // assign engine sounds to ships
2023 game_assign_sound_environment(); // assign the sound environment for this mission
2026 // call function in missionparse.cpp to fixup player/ai stuff.
2027 mission_parse_fixup_players();
2030 // Load in all the bitmaps for this level
2035 game_loading_callback_close();
2037 // the only thing we need to call on the standalone for now.
2039 // call function in missionparse.cpp to fixup player/ai stuff.
2040 mission_parse_fixup_players();
2042 // Load in all the bitmaps for this level
2047 time_t load_gl_init;
2048 time_t load_mission_load;
2049 time_t load_post_level_init;
2050 time_t load_mission_stuff;
2052 // tells the server to load the mission and initialize structures
2053 int game_start_mission()
2055 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2057 load_gl_init = time(NULL);
2059 load_gl_init = time(NULL) - load_gl_init;
2061 if (Game_mode & GM_MULTIPLAYER) {
2062 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2064 // clear multiplayer stats
2065 init_multiplayer_stats();
2068 load_mission_load = time(NULL);
2069 if (mission_load()) {
2070 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2071 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2072 gameseq_post_event(GS_EVENT_MAIN_MENU);
2074 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2079 load_mission_load = time(NULL) - load_mission_load;
2081 // If this is a red alert mission in campaign mode, bash wingman status
2082 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2083 red_alert_bash_wingman_status();
2086 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2087 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2088 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2090 game_load_palette();
2094 load_post_level_init = time(NULL);
2095 game_post_level_init();
2096 load_post_level_init = time(NULL) - load_post_level_init;
2100 void Do_model_timings_test();
2101 Do_model_timings_test();
2105 load_mission_stuff = time(NULL);
2106 freespace_mission_load_stuff();
2107 load_mission_stuff = time(NULL) - load_mission_stuff;
2112 int Interface_framerate = 0;
2115 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2116 DCF_BOOL( show_framerate, Show_framerate )
2117 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2118 DCF_BOOL( show_target_weapons, Show_target_weapons )
2119 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2120 DCF_BOOL( sound, Sound_enabled )
2121 DCF_BOOL( zbuffer, game_zbuffer )
2122 DCF_BOOL( shield_system, New_shield_system )
2123 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2124 DCF_BOOL( player_attacking, Player_attacking_enabled )
2125 DCF_BOOL( show_waypoints, Show_waypoints )
2126 DCF_BOOL( show_area_effect, Show_area_effect )
2127 DCF_BOOL( show_net_stats, Show_net_stats )
2128 DCF_BOOL( log, Log_debug_output_to_file )
2129 DCF_BOOL( training_msg_method, Training_msg_method )
2130 DCF_BOOL( show_player_pos, Show_player_pos )
2131 DCF_BOOL(i_framerate, Interface_framerate )
2133 DCF(show_mem,"Toggles showing mem usage")
2136 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2137 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2138 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2139 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2145 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2147 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2148 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2152 DCF(show_cpu,"Toggles showing cpu usage")
2155 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2156 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2157 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2158 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2164 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2166 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2167 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2174 // AL 4-8-98: always allow players to display their framerate
2177 DCF_BOOL( show_framerate, Show_framerate )
2184 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2187 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2188 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2189 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2190 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2192 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" );
2193 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2195 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2198 DCF(palette_flash,"Toggles palette flash effect on/off")
2201 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2202 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2203 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2204 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2206 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2207 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2210 int Use_low_mem = 0;
2212 DCF(low_mem,"Uses low memory settings regardless of RAM")
2215 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2216 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2217 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2218 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2220 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2221 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2223 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2227 int Framerate_delay = 0;
2229 float Freespace_gamma = 1.8f;
2231 DCF(gamma,"Sets Gamma factor")
2234 dc_get_arg(ARG_FLOAT|ARG_NONE);
2235 if ( Dc_arg_type & ARG_FLOAT ) {
2236 Freespace_gamma = Dc_arg_float;
2238 dc_printf( "Gamma reset to 1.0f\n" );
2239 Freespace_gamma = 1.0f;
2241 if ( Freespace_gamma < 0.1f ) {
2242 Freespace_gamma = 0.1f;
2243 } else if ( Freespace_gamma > 5.0f ) {
2244 Freespace_gamma = 5.0f;
2246 gr_set_gamma(Freespace_gamma);
2248 char tmp_gamma_string[32];
2249 SDL_snprintf( tmp_gamma_string, SDL_arraysize(tmp_gamma_string), NOX("%.2f"), Freespace_gamma );
2250 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2254 dc_printf( "Usage: gamma <float>\n" );
2255 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2256 Dc_status = 0; // don't print status if help is printed. Too messy.
2260 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2266 Game_current_mission_filename[0] = 0;
2268 // seed the random number generator
2269 Game_init_seed = (int)time(NULL);
2270 srand( Game_init_seed );
2272 Framerate_delay = 0;
2278 extern void bm_init();
2284 // Initialize the timer before the os
2291 //Initialize the libraries
2292 s1 = timer_get_milliseconds();
2295 if ( cfile_init() ) { // initialize before calling any cfopen stuff!!!
2300 e1 = timer_get_milliseconds();
2303 // time a bunch of cfopens
2305 s2 = timer_get_milliseconds();
2307 for(int idx=0; idx<10000; idx++){
2308 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2313 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2315 e2 = timer_get_milliseconds();
2318 os_init( Osreg_class_name, Osreg_app_name );
2319 os_set_title(Osreg_title);
2321 // initialize localization module. Make sure this is down AFTER initialzing OS.
2322 // int t1 = timer_get_milliseconds();
2323 lcl_init( detect_lang() );
2325 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2327 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2330 // verify that he has a valid weapons.tbl
2331 verify_weapons_tbl();
2333 // Output version numbers to registry for auto patching purposes
2334 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2335 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2336 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2338 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2339 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2340 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2342 // show the FPS counter if the config file says so
2343 Show_framerate = os_config_read_uint( "Video", "ShowFPS", Show_framerate );
2345 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2346 Asteroids_enabled = 1;
2349 /////////////////////////////
2351 /////////////////////////////
2353 if (!Is_standalone) {
2357 /////////////////////////////
2359 /////////////////////////////
2365 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2368 display_title_screen();
2372 // If less than 48MB of RAM, use low memory model.
2373 if ( (Freespace_total_ram < 48) || Use_low_mem ) {
2374 mprintf(( "Using normal memory settings...\n" ));
2375 bm_set_low_mem(1); // Use every other frame of bitmaps
2377 mprintf(( "Using high memory settings...\n" ));
2378 bm_set_low_mem(0); // Use all frames of bitmaps
2381 // load non-darkening pixel defs
2382 palman_load_pixels();
2384 // hud shield icon stuff
2385 hud_shield_game_init();
2387 control_config_common_init(); // sets up localization stuff in the control config
2393 gamesnd_parse_soundstbl();
2398 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2403 player_controls_init();
2406 //if(!Is_standalone){
2414 ship_init(); // read in ships.tbl
2416 mission_campaign_init(); // load in the default campaign
2418 // navmap_init(); // init the navigation map system
2419 context_help_init();
2420 techroom_intel_init(); // parse species.tbl, load intel info
2422 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2423 init_animating_pointer();
2425 mission_brief_common_init(); // Mark all the briefing structures as empty.
2426 gr_font_init(); // loads up all fonts
2428 neb2_init(); // fullneb stuff
2432 player_tips_init(); // helpful tips
2435 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2436 pilot_load_pic_list();
2437 pilot_load_squad_pic_list();
2439 load_animating_pointer(NOX("cursor"), 0, 0);
2441 // initialize alpha colors
2442 alpha_colors_init();
2445 // Game_music_paused = 0;
2448 if (Is_standalone) {
2449 std_init_standalone();
2452 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2453 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2455 mprintf(("cfile_init() took %d\n", e1 - s1));
2456 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2459 char transfer_text[128];
2461 float Start_time = 0.0f;
2463 float Framerate = 0.0f;
2465 float Timing_total = 0.0f;
2466 float Timing_render2 = 0.0f;
2467 float Timing_render3 = 0.0f;
2468 float Timing_flip = 0.0f;
2469 float Timing_clear = 0.0f;
2471 MONITOR(NumPolysDrawn);
2477 void game_get_framerate()
2479 char text[128] = "";
2481 if ( frame_int == -1 ) {
2483 for (i=0; i<FRAME_FILTER; i++ ) {
2484 frametimes[i] = 0.0f;
2489 frametotal -= frametimes[frame_int];
2490 frametotal += flFrametime;
2491 frametimes[frame_int] = flFrametime;
2492 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2494 if ( frametotal != 0.0 ) {
2495 if ( Framecount >= FRAME_FILTER )
2496 Framerate = FRAME_FILTER / frametotal;
2498 Framerate = Framecount / frametotal;
2499 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: %.1f"), Framerate );
2501 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: ?") );
2505 if (Show_framerate) {
2506 gr_set_color_fast(&HUD_color_debug);
2507 gr_string( 570, 2, text );
2511 void game_show_framerate()
2515 cur_time = f2fl(timer_get_approx_seconds());
2516 if (cur_time - Start_time > 30.0f) {
2517 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2518 Start_time += 1000.0f;
2521 //mprintf(( "%s\n", text ));
2524 if ( Debug_dump_frames )
2528 // possibly show control checking info
2529 control_check_indicate();
2531 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2532 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2533 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2534 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2537 if ( Show_cpu == 1 ) {
2542 dy = gr_get_font_height() + 1;
2544 gr_set_color_fast(&HUD_color_debug);
2547 extern int Gr_textures_in;
2548 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2551 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2553 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2555 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2557 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2559 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2564 extern int Num_pairs; // Number of object pairs that were checked.
2565 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2568 extern int Num_pairs_checked; // What percent of object pairs were checked.
2569 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2571 Num_pairs_checked = 0;
2575 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2578 if ( Timing_total > 0.01f ) {
2579 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2581 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2583 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2585 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2587 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2596 dy = gr_get_font_height() + 1;
2598 gr_set_color_fast(&HUD_color_debug);
2601 extern int TotalRam;
2602 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2607 extern int Model_ram;
2608 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2612 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2614 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2618 extern int Gr_textures_in;
2619 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2624 if ( Show_player_pos ) {
2628 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));
2631 MONITOR_INC(NumPolys, modelstats_num_polys);
2632 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2633 MONITOR_INC(NumVerts, modelstats_num_verts );
2635 modelstats_num_polys = 0;
2636 modelstats_num_polys_drawn = 0;
2637 modelstats_num_verts = 0;
2638 modelstats_num_sortnorms = 0;
2642 void game_show_standalone_framerate()
2644 float frame_rate=30.0f;
2645 if ( frame_int == -1 ) {
2647 for (i=0; i<FRAME_FILTER; i++ ) {
2648 frametimes[i] = 0.0f;
2653 frametotal -= frametimes[frame_int];
2654 frametotal += flFrametime;
2655 frametimes[frame_int] = flFrametime;
2656 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2658 if ( frametotal != 0.0 ) {
2659 if ( Framecount >= FRAME_FILTER ){
2660 frame_rate = FRAME_FILTER / frametotal;
2662 frame_rate = Framecount / frametotal;
2665 std_set_standalone_fps(frame_rate);
2669 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2670 void game_show_time_left()
2674 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2675 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2676 // checking how much time is left
2678 if ( Mission_end_time == -1 ){
2682 diff = f2i(Mission_end_time - Missiontime);
2683 // be sure to bash to 0. diff could be negative on frame that we quit mission
2688 hud_set_default_color();
2689 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2692 //========================================================================================
2693 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2694 //========================================================================================
2698 DCF(ai_pause,"Pauses ai")
2701 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2702 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2703 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2704 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2707 obj_init_all_ships_physics();
2710 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2711 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2714 DCF(single_step,"Single steps the game")
2717 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2718 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2719 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2720 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2722 last_single_step = 0; // Make so single step waits a frame before stepping
2725 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2726 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2729 DCF_BOOL(physics_pause, physics_paused)
2730 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2731 DCF_BOOL(ai_firing, Ai_firing_enabled )
2733 // Create some simple aliases to these commands...
2734 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2735 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2736 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2737 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2738 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2741 //========================================================================================
2742 //========================================================================================
2745 void game_training_pause_do()
2749 key = game_check_key();
2751 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2758 void game_increase_skill_level()
2761 if (Game_skill_level >= NUM_SKILL_LEVELS){
2762 Game_skill_level = 0;
2766 int Player_died_time;
2768 int View_percent = 100;
2771 DCF(view, "Sets the percent of the 3d view to render.")
2774 dc_get_arg(ARG_INT);
2775 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2776 View_percent = Dc_arg_int;
2778 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2784 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2788 dc_printf("View is set to %d%%\n", View_percent );
2793 // Set the clip region for the 3d rendering window
2794 void game_set_view_clip()
2796 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2797 // Set the clip region for the letterbox "dead view"
2798 int yborder = gr_screen.max_h/4;
2800 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2801 // J.S. I've changed my ways!! See the new "no constants" code!!!
2802 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2804 // Set the clip region for normal view
2805 if ( View_percent >= 100 ) {
2808 int xborder, yborder;
2810 if ( View_percent < 5 ) {
2814 float fp = i2fl(View_percent)/100.0f;
2815 int fi = fl2i(fl_sqrt(fp)*100.0f);
2816 if ( fi > 100 ) fi=100;
2818 xborder = ( gr_screen.max_w*(100-fi) )/200;
2819 yborder = ( gr_screen.max_h*(100-fi) )/200;
2821 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2827 void show_debug_stuff()
2830 int laser_count = 0, missile_count = 0;
2832 for (i=0; i<MAX_OBJECTS; i++) {
2833 if (Objects[i].type == OBJ_WEAPON){
2834 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2836 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2842 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2845 extern int Tool_enabled;
2847 time_t tst_time = 0;
2850 int tst_bitmap = -1;
2852 float tst_offset, tst_offset_total;
2855 void game_tst_frame_pre()
2863 g3_rotate_vertex(&v, &tst_pos);
2864 g3_project_vertex(&v);
2867 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2871 // big ship? always tst
2873 // within 3000 meters
2874 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2878 // within 300 meters
2879 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2886 void game_tst_frame()
2896 tst_time = time(NULL);
2898 // load the tst bitmap
2899 switch((int)frand_range(0.0f, 3.0)){
2901 tst_bitmap = bm_load("ig_jim");
2903 mprintf(("TST 0\n"));
2907 tst_bitmap = bm_load("ig_kan");
2909 mprintf(("TST 1\n"));
2913 tst_bitmap = bm_load("ig_jim");
2915 mprintf(("TST 2\n"));
2919 tst_bitmap = bm_load("ig_kan");
2921 mprintf(("TST 3\n"));
2930 // get the tst bitmap dimensions
2932 bm_get_info(tst_bitmap, &w, &h);
2935 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2937 snd_play(&Snds[SND_VASUDAN_BUP]);
2939 // tst x and direction
2943 tst_offset_total = (float)w;
2944 tst_offset = (float)w;
2946 tst_x = (float)gr_screen.max_w;
2947 tst_offset_total = (float)-w;
2948 tst_offset = (float)w;
2956 float diff = (tst_offset_total / 0.5f) * flFrametime;
2962 tst_offset -= fl_abs(diff);
2963 } else if(tst_mode == 2){
2966 tst_offset -= fl_abs(diff);
2970 gr_set_bitmap(tst_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2971 gr_bitmap((int)tst_x, (int)tst_y);
2974 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2978 // if we passed the switch point
2979 if(tst_offset <= 0.0f){
2984 tst_stamp = timestamp(1000);
2985 tst_offset = fl_abs(tst_offset_total);
2996 void game_tst_mark(object *objp, ship *shipp)
3005 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3008 sip = &Ship_info[shipp->ship_info_index];
3015 tst_pos = objp->pos;
3016 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3022 extern void render_shields();
3024 void player_repair_frame(float frametime)
3026 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3028 for(idx=0;idx<MAX_PLAYERS;idx++){
3031 np = &Net_players[idx];
3033 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)){
3035 // don't rearm/repair if the player is dead or dying/departing
3036 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3037 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3042 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3043 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3049 #define NUM_FRAMES_TEST 300
3050 #define NUM_MIXED_SOUNDS 16
3051 void do_timing_test(float flFrametime)
3053 static int framecount = 0;
3054 static int test_running = 0;
3055 static float test_time = 0.0f;
3057 static int snds[NUM_MIXED_SOUNDS];
3060 if ( test_running ) {
3062 test_time += flFrametime;
3063 if ( framecount >= NUM_FRAMES_TEST ) {
3065 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3066 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3071 if ( Test_begin == 1 ) {
3077 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3080 // start looping digital sounds
3081 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3082 snds[i] = snd_play_looping( &Snds[i], 0.0f);
3089 DCF(dcf_fov, "Change the field of view")
3092 dc_get_arg(ARG_FLOAT|ARG_NONE);
3093 if ( Dc_arg_type & ARG_NONE ) {
3094 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3095 dc_printf( "Zoom factor reset\n" );
3097 if ( Dc_arg_type & ARG_FLOAT ) {
3098 if (Dc_arg_float < 0.25f) {
3099 Viewer_zoom = 0.25f;
3100 dc_printf("Zoom factor pinned at 0.25.\n");
3101 } else if (Dc_arg_float > 1.25f) {
3102 Viewer_zoom = 1.25f;
3103 dc_printf("Zoom factor pinned at 1.25.\n");
3105 Viewer_zoom = Dc_arg_float;
3111 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3114 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3118 DCF(framerate_cap, "Sets the framerate cap")
3121 dc_get_arg(ARG_INT);
3122 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3123 Framerate_cap = Dc_arg_int;
3125 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3131 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3132 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3133 dc_printf("[n] must be from 1 to 120.\n");
3137 if ( Framerate_cap )
3138 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3140 dc_printf("There is no framerate cap currently active.\n");
3144 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3145 int Show_viewing_from_self = 0;
3147 void say_view_target()
3149 object *view_target;
3151 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3152 view_target = &Objects[Player_ai->target_objnum];
3154 view_target = Player_obj;
3156 if (Game_mode & GM_DEAD) {
3157 if (Player_ai->target_objnum != -1)
3158 view_target = &Objects[Player_ai->target_objnum];
3161 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3162 if (view_target != Player_obj){
3164 char *view_target_name = NULL;
3165 switch(Objects[Player_ai->target_objnum].type) {
3167 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3170 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3171 Viewer_mode &= ~VM_OTHER_SHIP;
3173 case OBJ_JUMP_NODE: {
3174 char jump_node_name[128];
3175 SDL_strlcpy(jump_node_name, XSTR( "jump node", 184), SDL_arraysize(jump_node_name));
3176 view_target_name = jump_node_name;
3177 Viewer_mode &= ~VM_OTHER_SHIP;
3186 if ( view_target_name ) {
3187 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3188 Show_viewing_from_self = 1;
3191 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3192 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3193 Show_viewing_from_self = 1;
3195 if (Show_viewing_from_self)
3196 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3201 Last_view_target = view_target;
3205 float Game_hit_x = 0.0f;
3206 float Game_hit_y = 0.0f;
3208 // Reset at the beginning of each frame
3209 void game_whack_reset()
3215 // Apply a 2d whack to the player
3216 void game_whack_apply( float x, float y )
3218 // Do some force feedback
3219 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3225 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3228 // call to apply a "shudder"
3229 void game_shudder_apply(int time, float intensity)
3231 Game_shudder_time = timestamp(time);
3232 Game_shudder_total = time;
3233 Game_shudder_intensity = intensity;
3236 #define FF_SCALE 10000
3237 void apply_hud_shake(matrix *eye_orient)
3239 if (Viewer_obj == Player_obj) {
3240 physics_info *pi = &Player_obj->phys_info;
3248 // Make eye shake due to afterburner
3249 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3252 dtime = timestamp_until(pi->afterburner_decay);
3256 tangles.p += 0.07f * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3257 tangles.h += 0.07f * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3260 // Make eye shake due to engine wash
3262 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3265 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX;
3266 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX;
3268 // get the intensity
3269 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3273 vm_vec_rand_vec_quick(&rand_vec);
3276 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3280 // make hud shake due to shuddering
3281 if(Game_shudder_time != -1){
3282 // if the timestamp has elapsed
3283 if(timestamp_elapsed(Game_shudder_time)){
3284 Game_shudder_time = -1;
3286 // otherwise apply some shudder
3290 dtime = timestamp_until(Game_shudder_time);
3294 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));
3295 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));
3300 vm_angles_2_matrix(&tm, &tangles);
3301 SDL_assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3302 SDL_assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3303 SDL_assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3304 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3309 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3311 // Player's velocity just before he blew up. Used to keep camera target moving.
3312 vector Dead_player_last_vel = { { { 1.0f, 1.0f, 1.0f } } };
3314 // Set eye_pos and eye_orient based on view mode.
3315 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3319 static int last_Viewer_mode = 0;
3320 static int last_Game_mode = 0;
3321 static int last_Viewer_objnum = -1;
3323 // This code is supposed to detect camera "cuts"... like going between
3326 // determine if we need to regenerate the nebula
3327 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3328 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3329 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3330 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3331 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3332 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3333 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3334 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3335 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3338 // regenerate the nebula
3342 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3343 //mprintf(( "************** Camera cut! ************\n" ));
3344 last_Viewer_mode = Viewer_mode;
3345 last_Game_mode = Game_mode;
3347 // Camera moved. Tell stars & debris to not do blurring.
3353 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3354 player_display_packlock_view();
3357 game_set_view_clip();
3359 if (Game_mode & GM_DEAD) {
3360 vector vec_to_deader, view_pos;
3363 Viewer_mode |= VM_DEAD_VIEW;
3365 if (Player_ai->target_objnum != -1) {
3366 int view_from_player = 1;
3368 if (Viewer_mode & VM_OTHER_SHIP) {
3369 // View from target.
3370 Viewer_obj = &Objects[Player_ai->target_objnum];
3372 last_Viewer_objnum = Player_ai->target_objnum;
3374 if ( Viewer_obj->type == OBJ_SHIP ) {
3375 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3376 view_from_player = 0;
3379 last_Viewer_objnum = -1;
3382 if ( view_from_player ) {
3383 // View target from player ship.
3385 *eye_pos = Player_obj->pos;
3386 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3387 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3390 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3392 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3393 dist += flFrametime * 16.0f;
3395 vm_vec_scale(&vec_to_deader, -dist);
3396 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3398 view_pos = Player_obj->pos;
3400 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3401 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3402 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3403 Dead_player_last_vel = Player_obj->phys_info.vel;
3404 //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));
3405 } else if (Player_ai->target_objnum != -1) {
3406 view_pos = Objects[Player_ai->target_objnum].pos;
3408 // Make camera follow explosion, but gradually slow down.
3409 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3410 view_pos = Player_obj->pos;
3411 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3412 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3415 *eye_pos = Dead_camera_pos;
3417 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3419 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3424 // if supernova shockwave
3425 if(supernova_camera_cut()){
3429 // call it dead view
3430 Viewer_mode |= VM_DEAD_VIEW;
3432 // set eye pos and orient
3433 supernova_set_view(eye_pos, eye_orient);
3435 // If already blown up, these other modes can override.
3436 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3437 Viewer_mode &= ~VM_DEAD_VIEW;
3439 Viewer_obj = Player_obj;
3441 if (Viewer_mode & VM_OTHER_SHIP) {
3442 if (Player_ai->target_objnum != -1){
3443 Viewer_obj = &Objects[Player_ai->target_objnum];
3444 last_Viewer_objnum = Player_ai->target_objnum;
3446 Viewer_mode &= ~VM_OTHER_SHIP;
3447 last_Viewer_objnum = -1;
3450 last_Viewer_objnum = -1;
3453 if (Viewer_mode & VM_EXTERNAL) {
3456 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3457 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3459 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3461 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3462 vm_vec_normalize(&eye_dir);
3463 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3466 // Modify the orientation based on head orientation.
3467 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3469 } else if ( Viewer_mode & VM_CHASE ) {
3472 if ( Viewer_obj->phys_info.speed < 0.1 )
3473 move_dir = Viewer_obj->orient.v.fvec;
3475 move_dir = Viewer_obj->phys_info.vel;
3476 vm_vec_normalize(&move_dir);
3479 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3480 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3481 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3482 vm_vec_normalize(&eye_dir);
3484 // JAS: I added the following code because if you slew up using
3485 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3486 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3487 // call because the up and the forward vector are the same. I fixed
3488 // it by adding in a fraction of the right vector all the time to the
3490 vector tmp_up = Viewer_obj->orient.v.uvec;
3491 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3493 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3496 // Modify the orientation based on head orientation.
3497 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3498 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3499 *eye_pos = Camera_pos;
3501 ship * shipp = &Ships[Player_obj->instance];
3503 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3504 vm_vec_normalize(&eye_dir);
3505 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3508 // get an eye position based upon the correct type of object
3509 switch(Viewer_obj->type){
3511 // make a call to get the eye point for the player object
3512 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3515 // make a call to get the eye point for the player object
3516 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3522 #ifdef JOHNS_DEBUG_CODE
3523 john_debug_stuff(&eye_pos, &eye_orient);
3529 apply_hud_shake(eye_orient);
3531 // setup neb2 rendering
3532 neb2_render_setup(eye_pos, eye_orient);
3536 extern void ai_debug_render_stuff();
3539 int Game_subspace_effect = 0;
3540 DCF_BOOL( subspace, Game_subspace_effect );
3542 // Does everything needed to render a frame
3543 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3547 g3_start_frame(game_zbuffer);
3548 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3550 // maybe offset the HUD (jitter stuff)
3551 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3552 HUD_set_offsets(Viewer_obj, !dont_offset);
3554 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3555 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3556 // must be done before ships are rendered
3557 if ( MULTIPLAYER_CLIENT ) {
3558 shield_point_multi_setup();
3561 if ( Game_subspace_effect ) {
3562 stars_draw(0,0,0,1);
3564 stars_draw(1,1,1,0);
3567 obj_render_all(obj_render);
3568 beam_render_all(); // render all beam weapons
3569 particle_render_all(); // render particles after everything else.
3570 trail_render_all(); // render missilie trails after everything else.
3571 mflash_render_all(); // render all muzzle flashes
3573 // Why do we not show the shield effect in these modes? Seems ok.
3574 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3578 // render nebula lightning
3581 // render local player nebula
3582 neb2_render_player();
3585 ai_debug_render_stuff();
3588 #ifndef RELEASE_REAL
3589 // game_framerate_check();
3593 extern void snd_spew_debug_info();
3594 snd_spew_debug_info();
3597 //================ END OF 3D RENDERING STUFF ====================
3601 if( (Game_detail_flags & DETAIL_FLAG_HUD) && (!(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )) ) {
3602 hud_maybe_clear_head_area();
3603 anim_render_all(0, flFrametime);
3606 extern int Multi_display_netinfo;
3607 if(Multi_display_netinfo){
3608 extern void multi_display_netinfo();
3609 multi_display_netinfo();
3612 game_tst_frame_pre();
3615 do_timing_test(flFrametime);
3619 extern int OO_update_index;
3620 multi_rate_display(OO_update_index, 375, 0);
3625 extern void oo_display();
3632 //#define JOHNS_DEBUG_CODE 1
3634 #ifdef JOHNS_DEBUG_CODE
3635 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3637 //if ( key_pressed(SDLK_LSHIFT) )
3639 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3641 model_subsystem *turret = tsys->system_info;
3643 if (turret->type == SUBSYSTEM_TURRET ) {
3644 vector v.fvec, v.uvec;
3645 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3647 ship_model_start(tobj);
3649 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3650 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3651 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3653 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3655 ship_model_stop(tobj);
3665 // following function for dumping frames for purposes of building trailers.
3668 // function to toggle state of dumping every frame into PCX when playing the game
3669 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3673 if ( Debug_dump_frames == 0 ) {
3675 Debug_dump_frames = 15;
3676 Debug_dump_trigger = 0;
3677 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3678 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3681 Debug_dump_frames = 0;
3682 Debug_dump_trigger = 0;
3683 gr_dump_frame_stop();
3684 dc_printf( "Frame dumping is now OFF\n" );
3690 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3694 if ( Debug_dump_frames == 0 ) {
3696 Debug_dump_frames = 15;
3697 Debug_dump_trigger = 1;
3698 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3699 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3702 Debug_dump_frames = 0;
3703 Debug_dump_trigger = 0;
3704 gr_dump_frame_stop();
3705 dc_printf( "Frame dumping is now OFF\n" );
3711 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3715 if ( Debug_dump_frames == 0 ) {
3717 Debug_dump_frames = 30;
3718 Debug_dump_trigger = 0;
3719 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3720 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3723 Debug_dump_frames = 0;
3724 Debug_dump_trigger = 0;
3725 gr_dump_frame_stop();
3726 dc_printf( "Frame dumping is now OFF\n" );
3732 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3736 if ( Debug_dump_frames == 0 ) {
3738 Debug_dump_frames = 30;
3739 Debug_dump_trigger = 1;
3740 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3741 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3744 Debug_dump_frames = 0;
3745 Debug_dump_trigger = 0;
3746 gr_dump_frame_stop();
3747 dc_printf( "Triggered frame dumping is now OFF\n" );
3753 void game_maybe_dump_frame()
3755 if ( !Debug_dump_frames ){
3759 if( Debug_dump_trigger && !key_pressed(SDLK_q) ){
3766 Debug_dump_frame_num++;
3772 extern int Player_dead_state;
3774 // Flip the page and time how long it took.
3775 void game_flip_page_and_time_it()
3780 t1 = timer_get_fixed_seconds();
3782 t2 = timer_get_fixed_seconds();
3785 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3786 SDL_snprintf( transfer_text, SDL_arraysize(transfer_text), NOX("%d MB/s"), fixmuldiv(t,65,d) );
3793 void game_simulation_frame()
3795 // blow ships up in multiplayer dogfight
3796 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){
3797 // blow up all non-player ships
3798 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3801 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3803 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)){
3804 moveup = GET_NEXT(moveup);
3807 shipp = &Ships[Objects[moveup->objnum].instance];
3808 sip = &Ship_info[shipp->ship_info_index];
3810 // only blow up small ships
3811 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3812 // function to simply explode a ship where it is currently at
3813 ship_self_destruct( &Objects[moveup->objnum] );
3816 moveup = GET_NEXT(moveup);
3822 // process AWACS stuff - do this first thing
3825 // single player, set Player hits_this_frame to 0
3826 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3827 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3828 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3832 supernova_process();
3833 if(supernova_active() >= 5){
3837 // fire targeting lasers now so that
3838 // 1 - created this frame
3839 // 2 - collide this frame
3840 // 3 - render this frame
3841 // 4 - ignored and deleted next frame
3842 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3844 ship_process_targeting_lasers();
3846 // do this here so that it works for multiplayer
3848 // get viewer direction
3849 int viewer_direction = PHYSICS_VIEWER_REAR;
3851 if(Viewer_mode == 0){
3852 viewer_direction = PHYSICS_VIEWER_FRONT;
3854 if(Viewer_mode & VM_PADLOCK_UP){
3855 viewer_direction = PHYSICS_VIEWER_UP;
3857 else if(Viewer_mode & VM_PADLOCK_REAR){
3858 viewer_direction = PHYSICS_VIEWER_REAR;
3860 else if(Viewer_mode & VM_PADLOCK_LEFT){
3861 viewer_direction = PHYSICS_VIEWER_LEFT;
3863 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3864 viewer_direction = PHYSICS_VIEWER_RIGHT;
3867 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3869 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3872 #define VM_PADLOCK_UP (1 << 7)
3873 #define VM_PADLOCK_REAR (1 << 8)
3874 #define VM_PADLOCK_LEFT (1 << 9)
3875 #define VM_PADLOCK_RIGHT (1 << 10)
3877 // evaluate mission departures and arrivals before we process all objects.
3878 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3880 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3881 // ships/wing packets.
3882 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3883 mission_parse_eval_stuff();
3886 // if we're an observer, move ourselves seperately from the standard physics
3887 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3888 obj_observer_move(flFrametime);
3891 // move all the objects now
3892 obj_move_all(flFrametime);
3894 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3895 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3896 // ship_check_cargo_all();
3897 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3898 mission_eval_goals();
3902 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3903 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3904 training_check_objectives();
3907 // do all interpolation now
3908 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3909 // client side processing of warping in effect stages
3910 multi_do_client_warp(flFrametime);
3912 // client side movement of an observer
3913 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3914 obj_observer_move(flFrametime);
3917 // move all objects - does interpolation now as well
3918 obj_move_all(flFrametime);
3921 // only process the message queue when the player is "in" the game
3922 if ( !Pre_player_entry ){
3923 message_queue_process(); // process any messages send to the player
3926 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3927 message_maybe_distort(); // maybe distort incoming message if comms damaged
3928 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3929 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3930 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3933 if(!(Game_mode & GM_STANDALONE_SERVER)){
3934 // process some stuff every frame (before frame is rendered)
3935 emp_process_local();
3937 hud_update_frame(); // update hud systems
3939 if (!physics_paused) {
3940 // Move particle system
3941 particle_move_all(flFrametime);
3943 // Move missile trails
3944 trail_move_all(flFrametime);
3946 // process muzzle flashes
3947 mflash_process_all();
3949 // Flash the gun flashes
3950 shipfx_flash_do_frame(flFrametime);
3952 shockwave_move_all(flFrametime); // update all the shockwaves
3955 // subspace missile strikes
3958 obj_snd_do_frame(); // update the object-linked persistant sounds
3959 game_maybe_update_sound_environment();
3960 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3962 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3964 if ( Game_subspace_effect ) {
3965 game_start_subspace_ambient_sound();
3971 // Maybe render and process the dead-popup
3972 void game_maybe_do_dead_popup(float frametime)
3974 if ( popupdead_is_active() ) {
3976 int choice = popupdead_do_frame(frametime);
3978 if ( Game_mode & GM_NORMAL ) {
3981 gameseq_post_event(GS_EVENT_ENTER_GAME);
3985 gameseq_post_event(GS_EVENT_END_GAME);
3989 gameseq_post_event(GS_EVENT_START_GAME);
3992 // this should only happen during a red alert mission
3995 SDL_assert(The_mission.red_alert);
3996 if(!The_mission.red_alert){
3997 gameseq_post_event(GS_EVENT_START_GAME);
4001 // choose the previous mission
4002 mission_campaign_previous_mission();
4004 gameseq_post_event(GS_EVENT_START_GAME);
4014 case POPUPDEAD_DO_MAIN_HALL:
4015 multi_quit_game(PROMPT_NONE,-1);
4018 case POPUPDEAD_DO_RESPAWN:
4019 multi_respawn_normal();
4020 event_music_player_respawn();
4023 case POPUPDEAD_DO_OBSERVER:
4024 multi_respawn_observer();
4025 event_music_player_respawn_as_observer();
4034 if ( leave_popup ) {
4040 // returns true if player is actually in a game_play stats
4041 int game_actually_playing()
4045 state = gameseq_get_state();
4046 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4052 // Draw the 2D HUD gauges
4053 void game_render_hud_2d()
4055 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4059 HUD_render_2d(flFrametime);
4063 // Draw the 3D-dependant HUD gauges
4064 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4066 g3_start_frame(0); // 0 = turn zbuffering off
4067 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4069 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4070 HUD_render_3d(flFrametime);
4074 game_sunspot_process(flFrametime);
4076 // Diminish the palette effect
4077 game_flash_diminish(flFrametime);
4085 int actually_playing;
4086 fix total_time1, total_time2;
4087 fix render2_time1=0, render2_time2=0;
4088 fix render3_time1=0, render3_time2=0;
4089 fix flip_time1=0, flip_time2=0;
4090 fix clear_time1=0, clear_time2=0;
4096 if (Framerate_delay) {
4097 int start_time = timer_get_milliseconds();
4098 while (timer_get_milliseconds() < start_time + Framerate_delay)
4104 demo_do_frame_start();
4106 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4111 // start timing frame
4112 timing_frame_start();
4114 total_time1 = timer_get_fixed_seconds();
4116 // var to hold which state we are in
4117 actually_playing = game_actually_playing();
4119 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4120 if (!(Game_mode & GM_STANDALONE_SERVER)){
4121 SDL_assert( OBJ_INDEX(Player_obj) >= 0 );
4125 if (Missiontime > Entry_delay_time){
4126 Pre_player_entry = 0;
4128 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4131 // Note: These are done even before the player enters, else buffers can overflow.
4132 if (! (Game_mode & GM_STANDALONE_SERVER)){
4136 shield_frame_init();
4138 if ( Player->control_mode != PCM_NORMAL )
4141 if ( !Pre_player_entry && actually_playing ) {
4142 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4144 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4145 game_process_keys();
4147 // don't read flying controls if we're playing a demo back
4148 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4149 read_player_controls( Player_obj, flFrametime);
4153 // if we're not the master, we may have to send the server-critical ship status button_info bits
4154 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4155 multi_maybe_send_ship_status();
4160 // Reset the whack stuff
4163 // These two lines must be outside of Pre_player_entry code,
4164 // otherwise too many lights are added.
4167 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4171 game_simulation_frame();
4173 // if not actually in a game play state, then return. This condition could only be true in
4174 // a multiplayer game.
4175 if ( !actually_playing ) {
4176 SDL_assert( Game_mode & GM_MULTIPLAYER );
4180 if (!Pre_player_entry) {
4181 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4182 clear_time1 = timer_get_fixed_seconds();
4183 // clear the screen to black
4185 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4189 clear_time2 = timer_get_fixed_seconds();
4190 render3_time1 = timer_get_fixed_seconds();
4191 game_render_frame_setup(&eye_pos, &eye_orient);
4192 game_render_frame( &eye_pos, &eye_orient );
4194 // save the eye position and orientation
4195 if ( Game_mode & GM_MULTIPLAYER ) {
4196 Net_player->s_info.eye_pos = eye_pos;
4197 Net_player->s_info.eye_orient = eye_orient;
4200 hud_show_target_model();
4202 // check to see if we should display the death died popup
4203 if(Game_mode & GM_DEAD_BLEW_UP){
4204 if(Game_mode & GM_MULTIPLAYER){
4205 // catch the situation where we're supposed to be warping out on this transition
4206 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4207 gameseq_post_event(GS_EVENT_DEBRIEF);
4208 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4209 Player_died_popup_wait = -1;
4213 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4214 Player_died_popup_wait = -1;
4220 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4221 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4222 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4223 if(!popupdead_is_active()){
4227 Player_multi_died_check = -1;
4231 render3_time2 = timer_get_fixed_seconds();
4232 render2_time1 = timer_get_fixed_seconds();
4235 game_get_framerate();
4236 game_show_framerate();
4238 game_show_time_left();
4240 // Draw the 2D HUD gauges
4241 if(supernova_active() < 3){
4242 game_render_hud_2d();
4245 game_set_view_clip();
4247 // Draw 3D HUD gauges
4248 game_render_hud_3d(&eye_pos, &eye_orient);
4252 render2_time2 = timer_get_fixed_seconds();
4254 // maybe render and process the dead popup
4255 game_maybe_do_dead_popup(flFrametime);
4257 // start timing frame
4258 timing_frame_stop();
4259 // timing_display(30, 10);
4261 // If a regular popup is active, don't flip (popup code flips)
4262 if( !popup_running_state() ){
4263 flip_time1 = timer_get_fixed_seconds();
4264 game_flip_page_and_time_it();
4265 flip_time2 = timer_get_fixed_seconds();
4269 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4272 game_show_standalone_framerate();
4276 game_do_training_checks();
4279 // process lightning (nebula only)
4282 total_time2 = timer_get_fixed_seconds();
4284 // Got some timing numbers
4285 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4286 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4287 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4288 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4289 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4292 demo_do_frame_end();
4294 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4300 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4301 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4302 // died. This resulted in screwed up death sequences.
4304 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4305 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4306 static int timer_paused=0;
4307 #if defined(TIMER_TEST) && !defined(NDEBUG)
4308 static int stop_count,start_count;
4309 static int time_stopped,time_started;
4311 int saved_timestamp_ticker = -1;
4313 void game_reset_time()
4315 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4319 // Last_time = timer_get_fixed_seconds();
4325 void game_stop_time()
4327 if (timer_paused==0) {
4329 time = timer_get_fixed_seconds();
4330 // Save how much time progressed so far in the frame so we can
4331 // use it when we unpause.
4332 Last_delta_time = time - Last_time;
4334 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4335 if (Last_delta_time < 0) {
4336 #if defined(TIMER_TEST) && !defined(NDEBUG)
4337 Int3(); //get Matt!!!!
4339 Last_delta_time = 0;
4341 #if defined(TIMER_TEST) && !defined(NDEBUG)
4342 time_stopped = time;
4345 // Stop the timer_tick stuff...
4346 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4347 saved_timestamp_ticker = timestamp_ticker;
4351 #if defined(TIMER_TEST) && !defined(NDEBUG)
4356 void game_start_time()
4359 SDL_assert(timer_paused >= 0);
4360 if (timer_paused==0) {
4362 time = timer_get_fixed_seconds();
4363 #if defined(TIMER_TEST) && !defined(NDEBUG)
4365 Int3(); //get Matt!!!!
4368 // Take current time, and set it backwards to account for time
4369 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4370 // will be correct when it goes to calculate the frametime next
4372 Last_time = time - Last_delta_time;
4373 #if defined(TIMER_TEST) && !defined(NDEBUG)
4374 time_started = time;
4377 // Restore the timer_tick stuff...
4378 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4379 SDL_assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4380 timestamp_ticker = saved_timestamp_ticker;
4381 saved_timestamp_ticker = -1;
4384 #if defined(TIMER_TEST) && !defined(NDEBUG)
4390 void game_set_frametime(int state)
4393 float frame_cap_diff;
4395 thistime = timer_get_fixed_seconds();
4397 if ( Last_time == 0 )
4398 Frametime = F1_0 / 30;
4400 Frametime = thistime - Last_time;
4402 // Frametime = F1_0 / 30;
4405 fix debug_frametime = Frametime; // Just used to display frametime.
4408 // If player hasn't entered mission yet, make frame take 1/4 second.
4409 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4412 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4414 fix frame_speed = F1_0 / Debug_dump_frames;
4416 if (Frametime > frame_speed ){
4417 nprintf(("warning","slow frame: %x\n",Frametime));
4420 thistime = timer_get_fixed_seconds();
4421 Frametime = thistime - Last_time;
4422 } while (Frametime < frame_speed );
4424 Frametime = frame_speed;
4428 SDL_assert( Framerate_cap > 0 );
4430 // Cap the framerate so it doesn't get too high.
4434 cap = F1_0/Framerate_cap;
4435 if (Frametime < cap) {
4436 thistime = cap - Frametime;
4437 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4438 SDL_Delay( fl2i(f2fl(thistime) * 1000.0f) );
4440 thistime = timer_get_fixed_seconds();
4444 if((Game_mode & GM_STANDALONE_SERVER) &&
4445 (f2fl(Frametime) < (1.0f/(float)Multi_options_g.std_framecap))){
4447 frame_cap_diff = (1.0f/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4448 SDL_Delay( fl2i(frame_cap_diff * 1000.0f) );
4450 thistime += fl2f((frame_cap_diff));
4452 Frametime = thistime - Last_time;
4455 // If framerate is too low, cap it.
4456 if (Frametime > MAX_FRAMETIME) {
4458 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4460 Frametime = MAX_FRAMETIME;
4463 Frametime = fixmul(Frametime, Game_time_compression);
4465 Last_time = thistime;
4466 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4468 flFrametime = f2fl(Frametime);
4469 //if(!(Game_mode & GM_PLAYING_DEMO)){
4470 timestamp_inc(flFrametime);
4472 /* if ((Framecount > 0) && (Framecount < 10)) {
4473 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4478 // This is called from game_do_frame(), and from navmap_do_frame()
4479 void game_update_missiontime()
4481 // TODO JAS: Put in if and move this into game_set_frametime,
4482 // fix navmap to call game_stop/start_time
4483 //if ( !timer_paused )
4484 Missiontime += Frametime;
4487 void game_do_frame()
4489 game_set_frametime(GS_STATE_GAME_PLAY);
4490 game_update_missiontime();
4492 if (Game_mode & GM_STANDALONE_SERVER) {
4493 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4496 if ( game_single_step && (last_single_step == game_single_step) ) {
4497 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4498 while( key_checkch() == 0 )
4500 os_set_title( XSTR( "FreeSpace", 171) );
4501 Last_time = timer_get_fixed_seconds();
4504 last_single_step = game_single_step;
4506 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4507 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4511 Keep_mouse_centered = 0;
4512 monitor_update(); // Update monitor variables
4515 void multi_maybe_do_frame()
4517 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4522 int Joymouse_button_status = 0;
4524 // Flush all input devices
4532 Joymouse_button_status = 0;
4534 //mprintf(("Game flush!\n" ));
4537 // function for multiplayer only which calls game_do_state_common() when running the
4539 void game_do_dc_networking()
4541 SDL_assert( Game_mode & GM_MULTIPLAYER );
4543 game_do_state_common( gameseq_get_state() );
4546 // Call this whenever in a loop, or when you need to check for a keystroke.
4547 int game_check_key()
4553 // convert keypad enter to normal enter
4554 if ((k & KEY_MASK) == SDLK_KP_ENTER)
4555 k = (k & ~KEY_MASK) | SDLK_RETURN;
4560 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4562 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4563 static int Demo_show_trailer_timestamp = 0;
4565 void demo_reset_trailer_timer()
4567 Demo_show_trailer_timestamp = timer_get_milliseconds();
4570 void demo_maybe_show_trailer(int k)
4573 // if key pressed, reset demo trailer timer
4575 demo_reset_trailer_timer();
4579 // if mouse moved, reset demo trailer timer
4582 mouse_get_delta(&dx, &dy);
4583 if ( (dx > 0) || (dy > 0) ) {
4584 demo_reset_trailer_timer();
4588 // if joystick has moved, reset demo trailer timer
4591 joy_get_delta(&dx, &dy);
4592 if ( (dx > 0) || (dy > 0) ) {
4593 demo_reset_trailer_timer();
4597 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4598 // the low-level code. Ugly, I know... but was the simplest and most
4601 // if 30 seconds since last demo trailer time reset, launch movie
4602 if ( os_foreground() ) {
4603 int now = timer_get_milliseconds();
4604 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4605 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4607 movie_play( NOX("fstrailer2.mve") );
4608 demo_reset_trailer_timer();
4616 // same as game_check_key(), except this is used while actually in the game. Since there
4617 // generally are differences between game control keys and general UI keys, makes sense to
4618 // have seperate functions for each case. If you are not checking a game control while in a
4619 // mission, you should probably be using game_check_key() instead.
4624 if (!os_foreground()) {
4629 // If we're in a single player game, pause it.
4630 if (!(Game_mode & GM_MULTIPLAYER)){
4631 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4632 game_process_pause_key();
4639 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4640 demo_maybe_show_trailer(k);
4643 // Move the mouse cursor with the joystick.
4644 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4645 // Move the mouse cursor with the joystick
4649 joy_get_pos( &jx, &jy, &jz, &jr );
4651 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4652 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4655 mouse_get_real_pos( &mx, &my );
4656 mouse_set_pos( mx+dx, my+dy );
4661 m = mouse_down(MOUSE_LEFT_BUTTON);
4663 if ( j != Joymouse_button_status ) {
4664 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4665 Joymouse_button_status = j;
4667 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4668 } else if ( (!j) && (m) ) {
4669 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4674 // if we should be ignoring keys because of some multiplayer situations
4675 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4679 // If a popup is running, don't process all the Fn keys
4680 if( popup_active() ) {
4684 state = gameseq_get_state();
4686 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4689 case KEY_DEBUGGED + SDLK_BACKSPACE:
4694 launch_context_help();
4699 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4701 // don't allow f2 while warping out in multiplayer
4702 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4707 case GS_STATE_INITIAL_PLAYER_SELECT:
4708 case GS_STATE_OPTIONS_MENU:
4709 case GS_STATE_HUD_CONFIG:
4710 case GS_STATE_CONTROL_CONFIG:
4711 case GS_STATE_DEATH_DIED:
4712 case GS_STATE_DEATH_BLEW_UP:
4713 case GS_STATE_VIEW_MEDALS:
4717 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4724 // hotkey selection screen -- only valid from briefing and beyond.
4726 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
4727 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) ) {
4728 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4734 case KEY_DEBUGGED + SDLK_F3:
4735 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4738 case KEY_DEBUGGED + SDLK_F4:
4739 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4743 if(Game_mode & GM_MULTIPLAYER){
4744 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4745 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4749 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4750 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4756 case SDLK_ESCAPE | KEY_SHIFTED:
4757 // make sure to quit properly out of multiplayer
4758 if(Game_mode & GM_MULTIPLAYER){
4759 multi_quit_game(PROMPT_NONE);
4762 gameseq_post_event( GS_EVENT_QUIT_GAME );
4767 case KEY_DEBUGGED + SDLK_p:
4770 case SDLK_PRINTSCREEN:
4772 static int counter = 0;
4777 SDL_snprintf( tmp_name, SDL_arraysize(tmp_name), NOX("screen%02d"), counter );
4779 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4780 gr_print_screen(tmp_name);
4788 case KEY_SHIFTED | SDLK_RETURN: {
4790 #if !defined(NDEBUG)
4792 if ( Game_mode & GM_NORMAL ){
4796 // if we're in multiplayer mode, do some special networking
4797 if(Game_mode & GM_MULTIPLAYER){
4798 debug_console(game_do_dc_networking);
4805 if ( Game_mode & GM_NORMAL )
4819 gameseq_post_event(GS_EVENT_QUIT_GAME);
4822 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4825 void camera_set_position( vector *pos )
4830 void camera_set_orient( matrix *orient )
4832 Camera_orient = *orient;
4835 void camera_set_velocity( vector *vel, int instantaneous )
4837 Camera_desired_velocity.xyz.x = 0.0f;
4838 Camera_desired_velocity.xyz.y = 0.0f;
4839 Camera_desired_velocity.xyz.z = 0.0f;
4841 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4842 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4843 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4845 if ( instantaneous ) {
4846 Camera_velocity = Camera_desired_velocity;
4854 vector new_vel, delta_pos;
4856 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4857 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4858 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4860 Camera_velocity = new_vel;
4862 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4864 vm_vec_add2( &Camera_pos, &delta_pos );
4866 float ot = Camera_time+0.0f;
4868 Camera_time += flFrametime;
4870 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4873 tmp.xyz.z = 4.739f; // always go this fast forward.
4875 // pick x and y velocities so they are always on a
4876 // circle with a 25 m radius.
4878 float tmp_angle = frand()*PI2;
4880 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4881 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4883 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4885 //mprintf(( "Changing velocity!\n" ));
4886 camera_set_velocity( &tmp, 0 );
4889 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4890 vector tmp = ZERO_VECTOR;
4891 camera_set_velocity( &tmp, 0 );
4896 void end_demo_campaign_do()
4898 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4899 // show upsell screens
4900 demo_upsell_show_screens();
4901 #elif defined(OEM_BUILD)
4902 // show oem upsell screens
4903 oem_upsell_show_screens();
4906 // drop into main hall
4907 gameseq_post_event( GS_EVENT_MAIN_MENU );
4910 // All code to process events. This is the only place
4911 // that you should change the state of the game.
4912 void game_process_event( int current_state, int event )
4914 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4917 case GS_EVENT_SIMULATOR_ROOM:
4918 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4921 case GS_EVENT_MAIN_MENU:
4922 gameseq_set_state(GS_STATE_MAIN_MENU);
4925 case GS_EVENT_OPTIONS_MENU:
4926 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4929 case GS_EVENT_BARRACKS_MENU:
4930 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4933 case GS_EVENT_TECH_MENU:
4934 gameseq_set_state(GS_STATE_TECH_MENU);
4937 case GS_EVENT_TRAINING_MENU:
4938 gameseq_set_state(GS_STATE_TRAINING_MENU);
4941 case GS_EVENT_START_GAME:
4942 Select_default_ship = 0;
4943 Player_multi_died_check = -1;
4944 gameseq_set_state(GS_STATE_CMD_BRIEF);
4947 case GS_EVENT_START_BRIEFING:
4948 gameseq_set_state(GS_STATE_BRIEFING);
4951 case GS_EVENT_DEBRIEF:
4952 // did we end the campaign in the main freespace 2 single player campaign?
4954 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace")) {
4956 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace2")) {
4958 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4960 gameseq_set_state(GS_STATE_DEBRIEF);
4963 Player_multi_died_check = -1;
4966 case GS_EVENT_SHIP_SELECTION:
4967 gameseq_set_state( GS_STATE_SHIP_SELECT );
4970 case GS_EVENT_WEAPON_SELECTION:
4971 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4974 case GS_EVENT_ENTER_GAME:
4976 // maybe start recording a demo
4978 demo_start_record("test.fsd");
4982 if (Game_mode & GM_MULTIPLAYER) {
4983 // if we're respawning, make sure we change the view mode so that the hud shows up
4984 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4988 gameseq_set_state(GS_STATE_GAME_PLAY);
4990 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4993 Player_multi_died_check = -1;
4995 // clear multiplayer button info
4996 extern button_info Multi_ship_status_bi;
4997 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4999 Start_time = f2fl(timer_get_approx_seconds());
5001 mprintf(("Entering game at time = %7.3f\n", Start_time));
5005 case GS_EVENT_START_GAME_QUICK:
5006 Select_default_ship = 1;
5007 gameseq_post_event(GS_EVENT_ENTER_GAME);
5011 case GS_EVENT_END_GAME:
5012 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5013 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5014 gameseq_set_state(GS_STATE_MAIN_MENU);
5019 Player_multi_died_check = -1;
5022 case GS_EVENT_QUIT_GAME:
5023 main_hall_stop_music();
5024 main_hall_stop_ambient();
5025 gameseq_set_state(GS_STATE_QUIT_GAME);
5027 Player_multi_died_check = -1;
5030 case GS_EVENT_GAMEPLAY_HELP:
5031 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5034 case GS_EVENT_PAUSE_GAME:
5035 gameseq_push_state(GS_STATE_GAME_PAUSED);
5038 case GS_EVENT_DEBUG_PAUSE_GAME:
5039 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5042 case GS_EVENT_TRAINING_PAUSE:
5043 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5046 case GS_EVENT_PREVIOUS_STATE:
5047 gameseq_pop_state();
5050 case GS_EVENT_TOGGLE_FULLSCREEN:
5051 gr_toggle_fullscreen();
5054 case GS_EVENT_TOGGLE_GLIDE:
5057 case GS_EVENT_LOAD_MISSION_MENU:
5060 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5061 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5064 case GS_EVENT_HUD_CONFIG:
5065 gameseq_push_state( GS_STATE_HUD_CONFIG );
5068 case GS_EVENT_CONTROL_CONFIG:
5069 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5072 case GS_EVENT_DEATH_DIED:
5073 gameseq_set_state( GS_STATE_DEATH_DIED );
5076 case GS_EVENT_DEATH_BLEW_UP:
5077 if ( current_state == GS_STATE_DEATH_DIED ) {
5078 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5079 event_music_player_death();
5081 // multiplayer clients set their extra check here
5082 if(Game_mode & GM_MULTIPLAYER){
5083 // set the multi died absolute last chance check
5084 Player_multi_died_check = time(NULL);
5087 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5091 case GS_EVENT_NEW_CAMPAIGN:
5092 if (!mission_load_up_campaign()){
5093 readyroom_continue_campaign();
5096 Player_multi_died_check = -1;
5099 case GS_EVENT_CAMPAIGN_CHEAT:
5100 if (!mission_load_up_campaign()){
5102 // bash campaign value
5103 extern char Main_hall_campaign_cheat[512];
5106 // look for the mission
5107 for(idx=0; idx<Campaign.num_missions; idx++){
5108 if(!SDL_strcasecmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5109 Campaign.next_mission = idx;
5110 Campaign.prev_mission = idx - 1;
5117 readyroom_continue_campaign();
5120 Player_multi_died_check = -1;
5123 case GS_EVENT_CAMPAIGN_ROOM:
5124 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5127 case GS_EVENT_CMD_BRIEF:
5128 gameseq_set_state(GS_STATE_CMD_BRIEF);
5131 case GS_EVENT_RED_ALERT:
5132 gameseq_set_state(GS_STATE_RED_ALERT);
5135 case GS_EVENT_CREDITS:
5136 gameseq_set_state( GS_STATE_CREDITS );
5139 case GS_EVENT_VIEW_MEDALS:
5140 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5143 case GS_EVENT_SHOW_GOALS:
5144 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5147 case GS_EVENT_HOTKEY_SCREEN:
5148 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5151 // multiplayer stuff follow these comments
5154 gameseq_set_state(GS_STATE_PXO);
5157 case GS_EVENT_PXO_HELP:
5158 gameseq_set_state(GS_STATE_PXO_HELP);
5161 case GS_EVENT_MULTI_JOIN_GAME:
5162 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5165 case GS_EVENT_MULTI_HOST_SETUP:
5166 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5169 case GS_EVENT_MULTI_CLIENT_SETUP:
5170 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5173 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5174 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5177 case GS_EVENT_MULTI_STD_WAIT:
5178 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5181 case GS_EVENT_STANDALONE_MAIN:
5182 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5185 case GS_EVENT_MULTI_PAUSE:
5186 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5189 case GS_EVENT_INGAME_PRE_JOIN:
5190 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5193 case GS_EVENT_EVENT_DEBUG:
5194 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5197 // Start a warpout where player automatically goes 70 no matter what
5198 // and can't cancel out of it.
5199 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5200 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5202 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5203 Player->saved_viewer_mode = Viewer_mode;
5204 Player->control_mode = PCM_WARPOUT_STAGE1;
5205 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5206 Warpout_time = 0.0f; // Start timer!
5209 case GS_EVENT_PLAYER_WARPOUT_START:
5210 if ( Player->control_mode != PCM_NORMAL ) {
5211 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5213 Player->saved_viewer_mode = Viewer_mode;
5214 Player->control_mode = PCM_WARPOUT_STAGE1;
5215 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5216 Warpout_time = 0.0f; // Start timer!
5217 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5221 case GS_EVENT_PLAYER_WARPOUT_STOP:
5222 if ( Player->control_mode != PCM_NORMAL ) {
5223 if ( !Warpout_forced ) { // cannot cancel forced warpout
5224 Player->control_mode = PCM_NORMAL;
5225 Viewer_mode = Player->saved_viewer_mode;
5226 hud_subspace_notify_abort();
5227 mprintf(( "Player put back to normal mode.\n" ));
5228 if ( Warpout_sound > -1 ) {
5229 snd_stop( Warpout_sound );
5236 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5237 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5238 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5239 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5241 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5242 shipfx_warpout_start( Player_obj );
5243 Player->control_mode = PCM_WARPOUT_STAGE2;
5244 Player->saved_viewer_mode = Viewer_mode;
5245 Viewer_mode |= VM_WARP_CHASE;
5247 vector tmp = Player_obj->pos;
5249 ship_get_eye( &tmp, &tmp_m, Player_obj );
5250 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5251 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5252 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5254 camera_set_position( &tmp );
5255 camera_set_orient( &Player_obj->orient );
5256 vector tmp_vel = { { { 0.0f, 5.1919f, 14.7f } } };
5258 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5259 camera_set_velocity( &tmp_vel, 1);
5263 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5264 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5265 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5266 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5268 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5269 Player->control_mode = PCM_WARPOUT_STAGE3;
5273 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5274 mprintf(( "Player warped out. Going to debriefing!\n" ));
5275 Player->control_mode = PCM_NORMAL;
5276 Viewer_mode = Player->saved_viewer_mode;
5279 // we have a special debriefing screen for multiplayer furballs
5280 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5281 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5283 // do the normal debriefing for all other situations
5285 gameseq_post_event(GS_EVENT_DEBRIEF);
5289 case GS_EVENT_STANDALONE_POSTGAME:
5290 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5293 case GS_EVENT_INITIAL_PLAYER_SELECT:
5294 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5297 case GS_EVENT_GAME_INIT:
5298 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5299 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5301 // see if the command line option has been set to use the last pilot, and act acoordingly
5302 if( player_select_get_last_pilot() ) {
5303 // always enter the main menu -- do the automatic network startup stuff elsewhere
5304 // so that we still have valid checks for networking modes, etc.
5305 gameseq_set_state(GS_STATE_MAIN_MENU);
5307 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5312 case GS_EVENT_MULTI_MISSION_SYNC:
5313 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5316 case GS_EVENT_MULTI_START_GAME:
5317 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5320 case GS_EVENT_MULTI_HOST_OPTIONS:
5321 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5324 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5325 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5328 case GS_EVENT_TEAM_SELECT:
5329 gameseq_set_state(GS_STATE_TEAM_SELECT);
5332 case GS_EVENT_END_CAMPAIGN:
5333 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5336 case GS_EVENT_END_DEMO:
5337 gameseq_set_state(GS_STATE_END_DEMO);
5340 case GS_EVENT_LOOP_BRIEF:
5341 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5350 // Called when a state is being left.
5351 // The current state is still at old_state, but as soon as
5352 // this function leaves, then the current state will become
5353 // new state. You should never try to change the state
5354 // in here... if you think you need to, you probably really
5355 // need to post an event, not change the state.
5356 void game_leave_state( int old_state, int new_state )
5358 int end_mission = 1;
5360 switch (new_state) {
5361 case GS_STATE_GAME_PAUSED:
5362 case GS_STATE_DEBUG_PAUSED:
5363 case GS_STATE_OPTIONS_MENU:
5364 case GS_STATE_CONTROL_CONFIG:
5365 case GS_STATE_MISSION_LOG_SCROLLBACK:
5366 case GS_STATE_DEATH_DIED:
5367 case GS_STATE_SHOW_GOALS:
5368 case GS_STATE_HOTKEY_SCREEN:
5369 case GS_STATE_MULTI_PAUSED:
5370 case GS_STATE_TRAINING_PAUSED:
5371 case GS_STATE_EVENT_DEBUG:
5372 case GS_STATE_GAMEPLAY_HELP:
5373 end_mission = 0; // these events shouldn't end a mission
5377 switch (old_state) {
5378 case GS_STATE_BRIEFING:
5379 brief_stop_voices();
5380 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5381 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5382 && (new_state != GS_STATE_TEAM_SELECT) ){
5383 common_select_close();
5384 if ( new_state == GS_STATE_MAIN_MENU ) {
5385 freespace_stop_mission();
5389 // COMMAND LINE OPTION
5390 if (Cmdline_multi_stream_chat_to_file){
5391 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5392 cfclose(Multi_chat_stream);
5396 case GS_STATE_DEBRIEF:
5397 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5402 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5403 multi_df_debrief_close();
5406 case GS_STATE_LOAD_MISSION_MENU:
5409 case GS_STATE_SIMULATOR_ROOM:
5413 case GS_STATE_CAMPAIGN_ROOM:
5414 campaign_room_close();
5417 case GS_STATE_CMD_BRIEF:
5418 if (new_state == GS_STATE_OPTIONS_MENU) {
5423 if (new_state == GS_STATE_MAIN_MENU)
5424 freespace_stop_mission();
5429 case GS_STATE_RED_ALERT:
5433 case GS_STATE_SHIP_SELECT:
5434 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5435 new_state != GS_STATE_HOTKEY_SCREEN &&
5436 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5437 common_select_close();
5438 if ( new_state == GS_STATE_MAIN_MENU ) {
5439 freespace_stop_mission();
5444 case GS_STATE_WEAPON_SELECT:
5445 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5446 new_state != GS_STATE_HOTKEY_SCREEN &&
5447 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5448 common_select_close();
5449 if ( new_state == GS_STATE_MAIN_MENU ) {
5450 freespace_stop_mission();
5455 case GS_STATE_TEAM_SELECT:
5456 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5457 new_state != GS_STATE_HOTKEY_SCREEN &&
5458 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5459 common_select_close();
5460 if ( new_state == GS_STATE_MAIN_MENU ) {
5461 freespace_stop_mission();
5466 case GS_STATE_MAIN_MENU:
5467 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5474 case GS_STATE_OPTIONS_MENU:
5475 //game_start_time();
5476 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5477 multi_join_clear_game_list();
5479 options_menu_close();
5482 case GS_STATE_BARRACKS_MENU:
5483 if(new_state != GS_STATE_VIEW_MEDALS){
5488 case GS_STATE_MISSION_LOG_SCROLLBACK:
5489 hud_scrollback_close();
5492 case GS_STATE_TRAINING_MENU:
5493 training_menu_close();
5496 case GS_STATE_GAME_PLAY:
5497 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5498 player_save_target_and_weapon_link_prefs();
5499 game_stop_looped_sounds();
5502 sound_env_disable();
5503 joy_ff_stop_effects();
5505 // stop game time under certain conditions
5506 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5511 // shut down any recording or playing demos
5516 // when in multiplayer and going back to the main menu, send a leave game packet
5517 // right away (before calling stop mission). stop_mission was taking to long to
5518 // close mission down and I want people to get notified ASAP.
5519 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5520 multi_quit_game(PROMPT_NONE);
5523 freespace_stop_mission();
5524 Game_time_compression = F1_0;
5528 case GS_STATE_TECH_MENU:
5532 case GS_STATE_TRAINING_PAUSED:
5533 Training_num_lines = 0;
5534 // fall through to GS_STATE_GAME_PAUSED
5536 case GS_STATE_GAME_PAUSED:
5538 if ( end_mission ) {
5543 case GS_STATE_DEBUG_PAUSED:
5546 pause_debug_close();
5550 case GS_STATE_HUD_CONFIG:
5554 // join/start a game
5555 case GS_STATE_MULTI_JOIN_GAME:
5556 if(new_state != GS_STATE_OPTIONS_MENU){
5557 multi_join_game_close();
5561 case GS_STATE_MULTI_HOST_SETUP:
5562 case GS_STATE_MULTI_CLIENT_SETUP:
5563 // if this is just the host going into the options screen, don't do anything
5564 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5568 // close down the proper state
5569 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5570 multi_create_game_close();
5572 multi_game_client_setup_close();
5575 // COMMAND LINE OPTION
5576 if (Cmdline_multi_stream_chat_to_file){
5577 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5578 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5579 cfclose(Multi_chat_stream);
5584 case GS_STATE_CONTROL_CONFIG:
5585 control_config_close();
5588 case GS_STATE_DEATH_DIED:
5589 Game_mode &= ~GM_DEAD_DIED;
5591 // early end while respawning or blowing up in a multiplayer game
5592 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5594 freespace_stop_mission();
5598 case GS_STATE_DEATH_BLEW_UP:
5599 Game_mode &= ~GM_DEAD_BLEW_UP;
5601 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5602 // to determine if I should do anything.
5603 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5605 freespace_stop_mission();
5608 // if we are not respawing as an observer or as a player, our new state will not
5609 // be gameplay state.
5610 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5611 game_stop_time(); // hasn't been called yet!!
5612 freespace_stop_mission();
5618 case GS_STATE_CREDITS:
5622 case GS_STATE_VIEW_MEDALS:
5626 case GS_STATE_SHOW_GOALS:
5627 mission_show_goals_close();
5630 case GS_STATE_HOTKEY_SCREEN:
5631 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5632 mission_hotkey_close();
5636 case GS_STATE_MULTI_MISSION_SYNC:
5637 // if we're moving into the options menu, don't do anything
5638 if(new_state == GS_STATE_OPTIONS_MENU){
5642 SDL_assert( Game_mode & GM_MULTIPLAYER );
5644 if ( new_state == GS_STATE_GAME_PLAY ){
5645 // palette_restore_palette();
5647 // change a couple of flags to indicate our state!!!
5648 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5649 send_netplayer_update_packet();
5651 // set the game mode
5652 Game_mode |= GM_IN_MISSION;
5656 case GS_STATE_VIEW_CUTSCENES:
5657 cutscenes_screen_close();
5660 case GS_STATE_MULTI_STD_WAIT:
5661 multi_standalone_wait_close();
5664 case GS_STATE_STANDALONE_MAIN:
5665 standalone_main_close();
5666 if(new_state == GS_STATE_MULTI_STD_WAIT){
5667 init_multiplayer_stats();
5671 case GS_STATE_MULTI_PAUSED:
5672 // if ( end_mission ){
5677 case GS_STATE_INGAME_PRE_JOIN:
5678 multi_ingame_select_close();
5681 case GS_STATE_STANDALONE_POSTGAME:
5682 multi_standalone_postgame_close();
5685 case GS_STATE_INITIAL_PLAYER_SELECT:
5686 player_select_close();
5689 case GS_STATE_MULTI_START_GAME:
5690 multi_start_game_close();
5693 case GS_STATE_MULTI_HOST_OPTIONS:
5694 multi_host_options_close();
5697 case GS_STATE_END_OF_CAMPAIGN:
5698 mission_campaign_end_close();
5701 case GS_STATE_LOOP_BRIEF:
5706 if (new_state != GS_STATE_PXO_HELP) {
5711 case GS_STATE_PXO_HELP:
5712 multi_pxo_help_close();
5717 // Called when a state is being entered.
5718 // The current state is set to the state we're entering at
5719 // this point, and old_state is set to the state we're coming
5720 // from. You should never try to change the state
5721 // in here... if you think you need to, you probably really
5722 // need to post an event, not change the state.
5724 void game_enter_state( int old_state, int new_state )
5726 switch (new_state) {
5727 case GS_STATE_MAIN_MENU:
5728 // in multiplayer mode, be sure that we are not doing networking anymore.
5729 if ( Game_mode & GM_MULTIPLAYER ) {
5730 SDL_assert( Net_player != NULL );
5731 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5734 Game_time_compression = F1_0;
5736 // determine which ship this guy is currently based on
5737 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5740 if (Player->on_bastion) {
5748 case GS_STATE_BRIEFING:
5749 main_hall_stop_music();
5750 main_hall_stop_ambient();
5752 if (Game_mode & GM_NORMAL) {
5753 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5754 // MWA: or from options or hotkey screens
5755 // JH: or if the command brief state already did this
5756 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5757 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5758 && (old_state != GS_STATE_CMD_BRIEF) ) {
5759 if ( !game_start_mission() ) // this should put us into a new state on failure!
5763 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5764 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5765 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5767 Game_time_compression = F1_0;
5769 if ( red_alert_mission() ) {
5770 gameseq_post_event(GS_EVENT_RED_ALERT);
5777 case GS_STATE_DEBRIEF:
5778 game_stop_looped_sounds();
5779 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5780 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5785 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5786 multi_df_debrief_init();
5789 case GS_STATE_LOAD_MISSION_MENU:
5792 case GS_STATE_SIMULATOR_ROOM:
5796 case GS_STATE_CAMPAIGN_ROOM:
5797 campaign_room_init();
5800 case GS_STATE_RED_ALERT:
5801 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5805 case GS_STATE_CMD_BRIEF: {
5806 int team_num = 0; // team number used as index for which cmd brief to use.
5808 if (old_state == GS_STATE_OPTIONS_MENU) {
5812 main_hall_stop_music();
5813 main_hall_stop_ambient();
5815 if (Game_mode & GM_NORMAL) {
5816 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5817 // MWA: or from options or hotkey screens
5818 // JH: or if the command brief state already did this
5819 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5820 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5821 if ( !game_start_mission() ) // this should put us into a new state on failure!
5826 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5827 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5828 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5830 cmd_brief_init(team_num);
5836 case GS_STATE_SHIP_SELECT:
5840 case GS_STATE_WEAPON_SELECT:
5841 weapon_select_init();
5844 case GS_STATE_TEAM_SELECT:
5848 case GS_STATE_GAME_PAUSED:
5853 case GS_STATE_DEBUG_PAUSED:
5854 // game_stop_time();
5855 // os_set_title("FreeSpace - PAUSED");
5858 case GS_STATE_TRAINING_PAUSED:
5865 case GS_STATE_OPTIONS_MENU:
5867 options_menu_init();
5870 case GS_STATE_GAME_PLAY:
5871 // coming from the gameplay state or the main menu, we might need to load the mission
5872 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5873 if ( !game_start_mission() ) // this should put us into a new state.
5878 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5879 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5880 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5881 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5882 (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)) ) {
5883 // JAS: Used to do all paging here.
5887 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5891 main_hall_stop_music();
5892 main_hall_stop_ambient();
5893 event_music_first_pattern(); // start the first pattern
5896 // special code that restores player ship selection and weapons loadout when doing a quick start
5897 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY)) ) {
5898 if ( !SDL_strcasecmp(Player_loadout.filename, Game_current_mission_filename) ) {
5899 wss_direct_restore_loadout();
5903 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5904 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5905 event_music_first_pattern(); // start the first pattern
5908 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5909 event_music_first_pattern(); // start the first pattern
5911 player_restore_target_and_weapon_link_prefs();
5913 Game_mode |= GM_IN_MISSION;
5916 // required to truely make mouse deltas zeroed in debug mouse code
5917 void mouse_force_pos(int x, int y);
5918 if (!Is_standalone) {
5919 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5925 // only start time if in single player, or coming from multi wait state
5928 (Game_mode & GM_NORMAL) &&
5929 (old_state != GS_STATE_VIEW_CUTSCENES)
5931 (Game_mode & GM_MULTIPLAYER) && (
5932 (old_state == GS_STATE_MULTI_PAUSED) ||
5933 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5939 // when coming from the multi paused state, reset the timestamps
5940 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5941 multi_reset_timestamps();
5944 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5945 // initialize all object update details
5946 multi_oo_gameplay_init();
5949 // under certain circumstances, the server should reset the object update rate limiting stuff
5950 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5951 ((old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC)) ){
5953 // reinitialize the rate limiting system for all clients
5954 multi_oo_rate_init_all();
5957 // multiplayer clients should always re-initialize their control info rate limiting system
5958 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5959 multi_oo_rate_init_all();
5963 if(Game_mode & GM_MULTIPLAYER){
5964 multi_ping_reset_players();
5967 Game_subspace_effect = 0;
5968 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5969 Game_subspace_effect = 1;
5970 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5971 game_start_subspace_ambient_sound();
5975 sound_env_set(&Game_sound_env);
5976 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5978 // clear multiplayer button info i
5979 extern button_info Multi_ship_status_bi;
5980 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5983 case GS_STATE_HUD_CONFIG:
5987 case GS_STATE_MULTI_JOIN_GAME:
5988 multi_join_clear_game_list();
5990 if (old_state != GS_STATE_OPTIONS_MENU) {
5991 multi_join_game_init();
5996 case GS_STATE_MULTI_HOST_SETUP:
5997 // don't reinitialize if we're coming back from the host options screen
5998 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5999 multi_create_game_init();
6004 case GS_STATE_MULTI_CLIENT_SETUP:
6005 if (old_state != GS_STATE_OPTIONS_MENU) {
6006 multi_game_client_setup_init();
6011 case GS_STATE_CONTROL_CONFIG:
6012 control_config_init();
6015 case GS_STATE_TECH_MENU:
6019 case GS_STATE_BARRACKS_MENU:
6020 if(old_state != GS_STATE_VIEW_MEDALS){
6025 case GS_STATE_MISSION_LOG_SCROLLBACK:
6026 hud_scrollback_init();
6029 case GS_STATE_DEATH_DIED:
6030 Player_died_time = timestamp(10);
6032 if(!(Game_mode & GM_MULTIPLAYER)){
6033 player_show_death_message();
6035 Game_mode |= GM_DEAD_DIED;
6038 case GS_STATE_DEATH_BLEW_UP:
6039 if ( !popupdead_is_active() ) {
6040 Player_ai->target_objnum = -1;
6043 // stop any local EMP effect
6046 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6047 Game_mode |= GM_DEAD_BLEW_UP;
6048 Show_viewing_from_self = 0;
6050 // timestamp how long we should wait before displaying the died popup
6051 if ( !popupdead_is_active() ) {
6052 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6056 case GS_STATE_GAMEPLAY_HELP:
6057 gameplay_help_init();
6060 case GS_STATE_CREDITS:
6061 main_hall_stop_music();
6062 main_hall_stop_ambient();
6066 case GS_STATE_VIEW_MEDALS:
6067 medal_main_init(Player);
6070 case GS_STATE_SHOW_GOALS:
6071 mission_show_goals_init();
6074 case GS_STATE_HOTKEY_SCREEN:
6075 mission_hotkey_init();
6078 case GS_STATE_MULTI_MISSION_SYNC:
6079 // if we're coming from the options screen, don't do any
6080 if(old_state == GS_STATE_OPTIONS_MENU){
6084 switch(Multi_sync_mode){
6085 case MULTI_SYNC_PRE_BRIEFING:
6086 // if moving from game forming to the team select state
6089 case MULTI_SYNC_POST_BRIEFING:
6090 // if moving from briefing into the mission itself
6093 // tell everyone that we're now loading data
6094 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6095 send_netplayer_update_packet();
6097 // JAS: Used to do all paging here!!!!
6099 Net_player->state = NETPLAYER_STATE_WAITING;
6100 send_netplayer_update_packet();
6102 Game_time_compression = F1_0;
6104 case MULTI_SYNC_INGAME:
6110 case GS_STATE_VIEW_CUTSCENES:
6111 cutscenes_screen_init();
6114 case GS_STATE_MULTI_STD_WAIT:
6115 multi_standalone_wait_init();
6118 case GS_STATE_STANDALONE_MAIN:
6119 // don't initialize if we're coming from one of these 2 states unless there are no
6120 // players left (reset situation)
6121 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6122 standalone_main_init();
6126 case GS_STATE_MULTI_PAUSED:
6130 case GS_STATE_INGAME_PRE_JOIN:
6131 multi_ingame_select_init();
6134 case GS_STATE_STANDALONE_POSTGAME:
6135 multi_standalone_postgame_init();
6138 case GS_STATE_INITIAL_PLAYER_SELECT:
6139 player_select_init();
6142 case GS_STATE_MULTI_START_GAME:
6143 multi_start_game_init();
6146 case GS_STATE_MULTI_HOST_OPTIONS:
6147 multi_host_options_init();
6150 case GS_STATE_END_OF_CAMPAIGN:
6151 mission_campaign_end_init();
6154 case GS_STATE_LOOP_BRIEF:
6159 if (old_state != GS_STATE_PXO_HELP) {
6161 // TODO: use_last_channel?
6167 case GS_STATE_PXO_HELP:
6168 multi_pxo_help_init();
6174 // do stuff that may need to be done regardless of state
6175 void game_do_state_common(int state,int no_networking)
6177 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6178 snd_do_frame(); // update sound system
6179 event_music_do_frame(); // music needs to play across many states
6181 multi_log_process();
6183 if (no_networking) {
6187 // maybe do a multiplayer frame based on game mode and state type
6188 if (Game_mode & GM_MULTIPLAYER) {
6190 case GS_STATE_OPTIONS_MENU:
6191 case GS_STATE_GAMEPLAY_HELP:
6192 case GS_STATE_HOTKEY_SCREEN:
6193 case GS_STATE_HUD_CONFIG:
6194 case GS_STATE_CONTROL_CONFIG:
6195 case GS_STATE_MISSION_LOG_SCROLLBACK:
6196 case GS_STATE_SHOW_GOALS:
6197 case GS_STATE_VIEW_CUTSCENES:
6198 case GS_STATE_EVENT_DEBUG:
6199 multi_maybe_do_frame();
6203 game_do_networking();
6207 // Called once a frame.
6208 // You should never try to change the state
6209 // in here... if you think you need to, you probably really
6210 // need to post an event, not change the state.
6211 int Game_do_state_should_skip = 0;
6212 void game_do_state(int state)
6214 // always lets the do_state_common() function determine if the state should be skipped
6215 Game_do_state_should_skip = 0;
6217 // legal to set the should skip state anywhere in this function
6218 game_do_state_common(state); // do stuff that may need to be done regardless of state
6220 if(Game_do_state_should_skip){
6225 case GS_STATE_MAIN_MENU:
6226 game_set_frametime(GS_STATE_MAIN_MENU);
6227 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6230 main_hall_do(flFrametime);
6234 case GS_STATE_OPTIONS_MENU:
6235 game_set_frametime(GS_STATE_OPTIONS_MENU);
6236 options_menu_do_frame(flFrametime);
6239 case GS_STATE_BARRACKS_MENU:
6240 game_set_frametime(GS_STATE_BARRACKS_MENU);
6241 barracks_do_frame(flFrametime);
6244 case GS_STATE_TRAINING_MENU:
6245 game_set_frametime(GS_STATE_TRAINING_MENU);
6246 training_menu_do_frame(flFrametime);
6249 case GS_STATE_TECH_MENU:
6250 game_set_frametime(GS_STATE_TECH_MENU);
6251 techroom_do_frame(flFrametime);
6254 case GS_STATE_GAMEPLAY_HELP:
6255 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6256 gameplay_help_do_frame(flFrametime);
6259 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6263 case GS_STATE_GAME_PAUSED:
6267 case GS_STATE_DEBUG_PAUSED:
6269 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6274 case GS_STATE_TRAINING_PAUSED:
6275 game_training_pause_do();
6278 case GS_STATE_LOAD_MISSION_MENU:
6282 case GS_STATE_BRIEFING:
6283 game_set_frametime(GS_STATE_BRIEFING);
6284 brief_do_frame(flFrametime);
6287 case GS_STATE_DEBRIEF:
6288 game_set_frametime(GS_STATE_DEBRIEF);
6289 debrief_do_frame(flFrametime);
6292 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6293 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6294 multi_df_debrief_do();
6297 case GS_STATE_SHIP_SELECT:
6298 game_set_frametime(GS_STATE_SHIP_SELECT);
6299 ship_select_do(flFrametime);
6302 case GS_STATE_WEAPON_SELECT:
6303 game_set_frametime(GS_STATE_WEAPON_SELECT);
6304 weapon_select_do(flFrametime);
6307 case GS_STATE_MISSION_LOG_SCROLLBACK:
6308 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6309 hud_scrollback_do_frame(flFrametime);
6312 case GS_STATE_HUD_CONFIG:
6313 game_set_frametime(GS_STATE_HUD_CONFIG);
6314 hud_config_do_frame(flFrametime);
6317 case GS_STATE_MULTI_JOIN_GAME:
6318 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6319 multi_join_game_do_frame();
6322 case GS_STATE_MULTI_HOST_SETUP:
6323 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6324 multi_create_game_do();
6327 case GS_STATE_MULTI_CLIENT_SETUP:
6328 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6329 multi_game_client_setup_do_frame();
6332 case GS_STATE_CONTROL_CONFIG:
6333 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6334 control_config_do_frame(flFrametime);
6337 case GS_STATE_DEATH_DIED:
6341 case GS_STATE_DEATH_BLEW_UP:
6345 case GS_STATE_SIMULATOR_ROOM:
6346 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6347 sim_room_do_frame(flFrametime);
6350 case GS_STATE_CAMPAIGN_ROOM:
6351 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6352 campaign_room_do_frame(flFrametime);
6355 case GS_STATE_RED_ALERT:
6356 game_set_frametime(GS_STATE_RED_ALERT);
6357 red_alert_do_frame(flFrametime);
6360 case GS_STATE_CMD_BRIEF:
6361 game_set_frametime(GS_STATE_CMD_BRIEF);
6362 cmd_brief_do_frame(flFrametime);
6365 case GS_STATE_CREDITS:
6366 game_set_frametime(GS_STATE_CREDITS);
6367 credits_do_frame(flFrametime);
6370 case GS_STATE_VIEW_MEDALS:
6371 game_set_frametime(GS_STATE_VIEW_MEDALS);
6375 case GS_STATE_SHOW_GOALS:
6376 game_set_frametime(GS_STATE_SHOW_GOALS);
6377 mission_show_goals_do_frame(flFrametime);
6380 case GS_STATE_HOTKEY_SCREEN:
6381 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6382 mission_hotkey_do_frame(flFrametime);
6385 case GS_STATE_VIEW_CUTSCENES:
6386 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6387 cutscenes_screen_do_frame();
6390 case GS_STATE_MULTI_STD_WAIT:
6391 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6392 multi_standalone_wait_do();
6395 case GS_STATE_STANDALONE_MAIN:
6396 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6397 standalone_main_do();
6400 case GS_STATE_MULTI_PAUSED:
6401 game_set_frametime(GS_STATE_MULTI_PAUSED);
6405 case GS_STATE_TEAM_SELECT:
6406 game_set_frametime(GS_STATE_TEAM_SELECT);
6410 case GS_STATE_INGAME_PRE_JOIN:
6411 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6412 multi_ingame_select_do();
6415 case GS_STATE_EVENT_DEBUG:
6417 game_set_frametime(GS_STATE_EVENT_DEBUG);
6418 game_show_event_debug(flFrametime);
6422 case GS_STATE_STANDALONE_POSTGAME:
6423 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6424 multi_standalone_postgame_do();
6427 case GS_STATE_INITIAL_PLAYER_SELECT:
6428 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6432 case GS_STATE_MULTI_MISSION_SYNC:
6433 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6437 case GS_STATE_MULTI_START_GAME:
6438 game_set_frametime(GS_STATE_MULTI_START_GAME);
6439 multi_start_game_do();
6442 case GS_STATE_MULTI_HOST_OPTIONS:
6443 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6444 multi_host_options_do();
6447 case GS_STATE_END_OF_CAMPAIGN:
6448 mission_campaign_end_do();
6451 case GS_STATE_END_DEMO:
6452 game_set_frametime(GS_STATE_END_DEMO);
6453 end_demo_campaign_do();
6456 case GS_STATE_LOOP_BRIEF:
6457 game_set_frametime(GS_STATE_LOOP_BRIEF);
6462 game_set_frametime(GS_STATE_PXO);
6466 case GS_STATE_PXO_HELP:
6467 game_set_frametime(GS_STATE_PXO_HELP);
6468 multi_pxo_help_do();
6471 } // end switch(gs_current_state)
6475 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6476 int game_do_ram_check(int ram_in_mbytes)
6478 if ( ram_in_mbytes < 30 ) {
6479 int allowed_to_run = 1;
6480 if ( ram_in_mbytes < 25 ) {
6486 if ( allowed_to_run ) {
6487 SDL_MessageBoxData mboxd;
6488 SDL_MessageBoxButtonData mboxbuttons[2];
6491 // not a translated string, but it's too long and smartdrv isn't
6492 // really a thing for any OS we now support :p
6493 // 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);
6494 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);
6496 mboxbuttons[0].buttonid = 0;
6497 mboxbuttons[0].text = XSTR("Ok", 503);
6498 mboxbuttons[0].flags = 0;
6500 mboxbuttons[1].buttonid = 1;
6501 mboxbuttons[1].text = XSTR("Cancel", 504);
6502 mboxbuttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
6504 mboxd.flags = SDL_MESSAGEBOX_ERROR;
6505 mboxd.title = XSTR( "Not Enough RAM", 194);
6506 mboxd.message = tmp;
6507 mboxd.numbuttons = 2;
6508 mboxd.buttons = mboxbuttons;
6509 mboxd.window = NULL;
6510 mboxd.colorScheme = NULL;
6512 SDL_ShowMessageBox(&mboxd, &msgbox_rval);
6514 if ( msgbox_rval == 1 ) {
6518 // not a translated string, but it's too long and smartdrv isn't
6519 // really a thing for any OS we now support :p
6520 // 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);
6521 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);
6523 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough RAM", 194), tmp, NULL);
6532 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6533 // If so, copy it over and remove the update directory.
6534 void game_maybe_update_launcher(char *exe_dir)
6539 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6543 int sub_total_destroyed = 0;
6547 // get the total for all his children
6548 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6549 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6552 // find the # of faces for this _individual_ object
6553 total = submodel_get_num_polys(model_num, sm);
6554 if(strstr(pm->submodel[sm].name, "-destroyed")){
6555 sub_total_destroyed = total;
6559 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6562 *out_total += total + sub_total;
6563 *out_destroyed_total += sub_total_destroyed;
6566 #define BAIL() do { int idx; for(idx=0; idx<num_files; idx++){ if(pof_list[idx] != NULL){free(pof_list[idx]); pof_list[idx] = NULL;}} return;} while(0);
6567 void game_spew_pof_info()
6569 char *pof_list[1000];
6572 int idx, model_num, i, j;
6574 int total, root_total, model_total, destroyed_total, counted;
6578 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6580 // spew info on all the pofs
6586 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6591 for(idx=0; idx<num_files; idx++, counted++){
6592 SDL_snprintf(str, SDL_arraysize(str), "%s.pof", pof_list[idx]);
6593 model_num = model_load(str, 0, NULL);
6595 pm = model_get(model_num);
6597 // if we have a real model
6602 // go through and print all raw submodels
6603 cfputs("RAW\n", out);
6606 for (i=0; i<pm->n_models; i++) {
6607 total = submodel_get_num_polys(model_num, i);
6609 model_total += total;
6610 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6613 SDL_snprintf(str, SDL_arraysize(str), "Model total %d\n", model_total);
6616 // now go through and do it by LOD
6617 cfputs("BY LOD\n\n", out);
6618 for(i=0; i<pm->n_detail_levels; i++){
6619 SDL_snprintf(str, SDL_arraysize(str), "LOD %d\n", i);
6623 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6625 destroyed_total = 0;
6626 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6627 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6630 SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6633 SDL_snprintf(str, SDL_arraysize(str), "TOTAL: %d\n", total + root_total);
6635 SDL_snprintf(str, SDL_arraysize(str), "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6637 SDL_snprintf(str, SDL_arraysize(str), "TOTAL destroyed faces %d\n\n", destroyed_total);
6640 cfputs("------------------------------------------------------------------------\n\n", out);
6644 if(counted >= MAX_POLYGON_MODELS - 5){
6657 game_spew_pof_info();
6660 int game_main(const char *szCmdLine)
6664 // Find out how much RAM is on this machine
6665 Freespace_total_ram = SDL_GetSystemRAM();
6667 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6671 if (!vm_init(24*1024*1024)) {
6672 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);
6676 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6678 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);
6687 extern void windebug_memwatch_init();
6688 windebug_memwatch_init();
6696 mprintf(("Platform: %s\n", SDL_GetPlatform()));
6697 mprintf(("CPU: %d %s\n", SDL_GetCPUCount(), (SDL_GetCPUCount() == 1) ? "core" : "cores"));
6698 mprintf(("Memory: %dMB\n", Freespace_total_ram));
6699 mprintf(("Build: %d-bit, %s-endian\n", sizeof(void*) * 8, (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? "little" : "big"));
6701 parse_cmdline(szCmdLine);
6703 mprintf(("--------------------------------------------------------------------------------\n"));
6705 #ifdef STANDALONE_ONLY_BUILD
6707 nprintf(("Network", "Standalone running"));
6710 nprintf(("Network", "Standalone running"));
6717 // maybe spew pof stuff
6718 if(Cmdline_spew_pof_info){
6719 game_spew_pof_info();
6724 // non-demo, non-standalone, play the intro movie
6726 if ( !Is_standalone ) {
6728 // release -- movies always play
6731 // 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
6732 movie_play( NOX("intro.mve") );
6734 // debug version, movie will only play with -showmovies
6735 #elif !defined(NDEBUG)
6737 movie_play( NOX("intro.mve") );
6740 if ( Cmdline_show_movies )
6741 movie_play( NOX("intro.mve") );
6750 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6752 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6756 // only important for non THREADED mode
6759 state = gameseq_process_events();
6760 if ( state == GS_STATE_QUIT_GAME ){
6765 #if defined(FS2_DEMO) || defined(FS1_DEMO)
6767 demo_upsell_show_screens();
6769 #elif defined(OEM_BUILD)
6770 // show upsell screens on exit
6771 oem_upsell_show_screens();
6778 // launcher the fslauncher program on exit
6779 void game_launch_launcher_on_exit()
6787 // This function is called when FreeSpace terminates normally.
6789 void game_shutdown(void)
6791 // don't ever flip a page on the standalone!
6792 if(!(Game_mode & GM_STANDALONE_SERVER)){
6798 // if the player has left the "player select" screen and quit the game without actually choosing
6799 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6800 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6804 // load up common multiplayer icons
6805 multi_unload_common_icons();
6807 shockwave_close(); // release any memory used by shockwave system
6808 fireball_close(); // free fireball system
6809 ship_close(); // free any memory that was allocated for the ships
6810 weapon_close(); // free any memory that was allocated for the weapons
6811 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6812 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6813 bm_unload_all(); // free bitmaps
6814 mission_campaign_close(); // close out the campaign stuff
6815 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
6816 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6818 #ifdef MULTI_USE_LAG
6822 // the menu close functions will unload the bitmaps if they were displayed during the game
6823 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6826 context_help_close(); // close out help system
6827 training_menu_close();
6828 lcl_close(); // be sure localization is closed out
6831 // free left-over memory from parsed tables
6832 cutscene_tbl_close();
6834 scoring_tbl_close();
6835 player_tips_close();
6837 extern void joy_close();
6840 audiostream_close();
6842 event_music_close();
6846 // HACKITY HACK HACK
6847 // if this flag is set, we should be firing up the launcher when exiting freespace
6848 extern int Multi_update_fireup_launcher_on_exit;
6849 if(Multi_update_fireup_launcher_on_exit){
6850 game_launch_launcher_on_exit();
6854 // game_stop_looped_sounds()
6856 // This function will call the appropriate stop looped sound functions for those
6857 // modules which use looping sounds. It is not enough just to stop a looping sound
6858 // at the DirectSound level, the game is keeping track of looping sounds, and this
6859 // function is used to inform the game that looping sounds are being halted.
6861 void game_stop_looped_sounds()
6863 hud_stop_looped_locking_sounds();
6864 hud_stop_looped_engine_sounds();
6865 afterburner_stop_sounds();
6866 player_stop_looped_sounds();
6867 obj_snd_stop_all(); // stop all object-linked persistant sounds
6868 game_stop_subspace_ambient_sound();
6869 snd_stop(Radar_static_looping);
6870 Radar_static_looping = -1;
6871 snd_stop(Target_static_looping);
6872 shipfx_stop_engine_wash_sound();
6873 Target_static_looping = -1;
6876 //////////////////////////////////////////////////////////////////////////
6878 // Code for supporting an animating mouse pointer
6881 //////////////////////////////////////////////////////////////////////////
6883 typedef struct animating_obj
6892 static animating_obj Animating_mouse;
6894 // ----------------------------------------------------------------------------
6895 // init_animating_pointer()
6897 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6898 // gets properly initialized
6900 void init_animating_pointer()
6902 Animating_mouse.first_frame = -1;
6903 Animating_mouse.num_frames = 0;
6904 Animating_mouse.current_frame = -1;
6905 Animating_mouse.time = 0.0f;
6906 Animating_mouse.elapsed_time = 0.0f;
6909 // ----------------------------------------------------------------------------
6910 // load_animating_pointer()
6912 // Called at game init to load in the frames for the animating mouse pointer
6914 // input: filename => filename of animation file that holds the animation
6916 void load_animating_pointer(const char *filename, int dx, int dy)
6921 init_animating_pointer();
6923 am = &Animating_mouse;
6924 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
6925 if ( am->first_frame == -1 )
6926 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
6927 am->current_frame = 0;
6928 am->time = am->num_frames / i2fl(fps);
6931 // ----------------------------------------------------------------------------
6932 // unload_animating_pointer()
6934 // Called at game shutdown to free the memory used to store the animation frames
6936 void unload_animating_pointer()
6941 am = &Animating_mouse;
6942 for ( i = 0; i < am->num_frames; i++ ) {
6943 SDL_assert( (am->first_frame+i) >= 0 );
6944 bm_release(am->first_frame + i);
6947 am->first_frame = -1;
6949 am->current_frame = -1;
6952 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
6953 void game_render_mouse(float frametime)
6958 // if animating cursor exists, play the next frame
6959 am = &Animating_mouse;
6960 if ( am->first_frame != -1 ) {
6961 mouse_get_pos(&mx, &my);
6962 am->elapsed_time += frametime;
6963 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
6964 if ( am->current_frame >= am->num_frames ) {
6965 am->current_frame = 0;
6966 am->elapsed_time = 0.0f;
6968 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
6972 // ----------------------------------------------------------------------------
6973 // game_maybe_draw_mouse()
6975 // determines whether to draw the mouse pointer at all, and what frame of
6976 // animation to use if the mouse is animating
6978 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
6980 // input: frametime => elapsed frame time in seconds since last call
6982 void game_maybe_draw_mouse(float frametime)
6986 game_state = gameseq_get_state();
6988 switch ( game_state ) {
6989 case GS_STATE_GAME_PAUSED:
6990 // case GS_STATE_MULTI_PAUSED:
6991 case GS_STATE_GAME_PLAY:
6992 case GS_STATE_DEATH_DIED:
6993 case GS_STATE_DEATH_BLEW_UP:
6994 if ( popup_active() || popupdead_is_active() ) {
7006 if ( !Mouse_hidden )
7007 game_render_mouse(frametime);
7011 void game_do_training_checks()
7015 waypoint_list *wplp;
7017 if (Training_context & TRAINING_CONTEXT_SPEED) {
7018 s = (int) Player_obj->phys_info.fspeed;
7019 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7020 if (!Training_context_speed_set) {
7021 Training_context_speed_set = 1;
7022 Training_context_speed_timestamp = timestamp();
7026 Training_context_speed_set = 0;
7029 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7030 wplp = &Waypoint_lists[Training_context_path];
7031 if (wplp->count > Training_context_goal_waypoint) {
7032 i = Training_context_goal_waypoint;
7034 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7035 if (d <= Training_context_distance) {
7036 Training_context_at_waypoint = i;
7037 if (Training_context_goal_waypoint == i) {
7038 Training_context_goal_waypoint++;
7039 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7046 if (i == wplp->count)
7049 } while (i != Training_context_goal_waypoint);
7053 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7054 Players_target = Player_ai->target_objnum;
7055 Players_targeted_subsys = Player_ai->targeted_subsys;
7056 Players_target_timestamp = timestamp();
7060 /////////// Following is for event debug view screen
7064 #define EVENT_DEBUG_MAX 5000
7065 #define EVENT_DEBUG_EVENT 0x8000
7067 int Event_debug_index[EVENT_DEBUG_MAX];
7070 void game_add_event_debug_index(int n, int indent)
7072 if (ED_count < EVENT_DEBUG_MAX)
7073 Event_debug_index[ED_count++] = n | (indent << 16);
7076 void game_add_event_debug_sexp(int n, int indent)
7081 if (Sexp_nodes[n].first >= 0) {
7082 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7083 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7087 game_add_event_debug_index(n, indent);
7088 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7089 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7091 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7094 void game_event_debug_init()
7099 for (e=0; e<Num_mission_events; e++) {
7100 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7101 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7105 void game_show_event_debug(float frametime)
7109 int font_height, font_width;
7111 static int scroll_offset = 0;
7113 k = game_check_key();
7119 if (scroll_offset < 0)
7129 scroll_offset -= 20;
7130 if (scroll_offset < 0)
7135 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7139 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7145 gr_set_color_fast(&Color_bright);
7147 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7149 gr_set_color_fast(&Color_normal);
7151 gr_get_string_size(&font_width, &font_height, NOX("test"));
7152 y_max = gr_screen.max_h - font_height - 5;
7156 while (k < ED_count) {
7157 if (y_index > y_max)
7160 z = Event_debug_index[k];
7161 if (z & EVENT_DEBUG_EVENT) {
7163 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7164 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7165 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7166 Mission_events[z].repeat_count, Mission_events[z].interval);
7174 SDL_strlcat(buf, Sexp_nodes[z & 0x7fff].text, SDL_arraysize(buf));
7175 switch (Sexp_nodes[z & 0x7fff].value) {
7177 SDL_strlcat(buf, NOX(" (True)"), SDL_arraysize(buf));
7181 SDL_strlcat(buf, NOX(" (False)"), SDL_arraysize(buf));
7184 case SEXP_KNOWN_TRUE:
7185 SDL_strlcat(buf, NOX(" (Always true)"), SDL_arraysize(buf));
7188 case SEXP_KNOWN_FALSE:
7189 SDL_strlcat(buf, NOX(" (Always false)"), SDL_arraysize(buf));
7192 case SEXP_CANT_EVAL:
7193 SDL_strlcat(buf, NOX(" (Can't eval)"), SDL_arraysize(buf));
7197 case SEXP_NAN_FOREVER:
7198 SDL_strlcat(buf, NOX(" (Not a number)"), SDL_arraysize(buf));
7203 gr_printf(10, y_index, buf);
7204 y_index += font_height;
7217 int Tmap_num_too_big = 0;
7218 int Num_models_needing_splitting = 0;
7220 void Time_model( int modelnum )
7222 // mprintf(( "Timing ship '%s'\n", si->name ));
7224 vector eye_pos, model_pos;
7225 matrix eye_orient, model_orient;
7227 polymodel *pm = model_get( modelnum );
7229 int l = strlen(pm->filename);
7231 if ( (l == '/') || (l=='\\') || (l==':')) {
7237 char *pof_file = &pm->filename[l];
7239 int model_needs_splitting = 0;
7241 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7243 for (i=0; i<pm->n_textures; i++ ) {
7244 char filename[1024];
7247 int bmp_num = pm->original_textures[i];
7248 if ( bmp_num > -1 ) {
7249 bm_get_palette(pm->original_textures[i], pal, filename, SDL_arraysize(filename) );
7251 bm_get_info( pm->original_textures[i],&w, &h );
7254 if ( (w > 512) || (h > 512) ) {
7255 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7257 model_needs_splitting++;
7260 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7264 if ( model_needs_splitting ) {
7265 Num_models_needing_splitting++;
7267 eye_orient = model_orient = vmd_identity_matrix;
7268 eye_pos = model_pos = vmd_zero_vector;
7270 eye_pos.xyz.z = -pm->rad*2.0f;
7272 vector eye_to_model;
7274 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7275 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7277 fix t1 = timer_get_fixed_seconds();
7280 ta.p = ta.b = ta.h = 0.0f;
7283 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7285 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7287 modelstats_num_polys = modelstats_num_verts = 0;
7289 while( ta.h < PI2 ) {
7292 vm_angles_2_matrix(&m1, &ta );
7293 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7300 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7302 model_clear_instance( modelnum );
7303 model_set_detail_level(0); // use highest detail level
7304 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7312 int k = key_inkey();
7313 if ( k == SDLK_ESCAPE ) {
7318 fix t2 = timer_get_fixed_seconds();
7320 if (framecount < 1) {
7324 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7325 //bitmaps_used_this_frame /= framecount;
7327 modelstats_num_polys /= framecount;
7328 modelstats_num_verts /= framecount;
7330 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7331 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 );
7333 // 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 );
7339 int Time_models = 0;
7340 DCF_BOOL( time_models, Time_models );
7342 void Do_model_timings_test()
7346 if ( !Time_models ) return;
7348 mprintf(( "Timing models!\n" ));
7352 ubyte model_used[MAX_POLYGON_MODELS];
7353 int model_id[MAX_POLYGON_MODELS];
7354 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7359 for (i=0; i<Num_ship_types; i++ ) {
7360 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7362 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7363 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7366 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7367 if ( !Texture_fp ) return;
7369 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7370 if ( !Time_fp ) return;
7372 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7373 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7375 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7376 if ( model_used[i] ) {
7377 Time_model( model_id[i] );
7381 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7382 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7391 // Call this function when you want to inform the player that a feature is not
7392 // enabled in the DEMO version of FreSpace
7393 void game_feature_not_in_demo_popup()
7395 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7398 // format the specified time (fixed point) into a nice string
7399 void game_format_time(fix m_time, char *time_str, const int time_str_len)
7402 int hours,minutes,seconds;
7404 mtime = f2fl(m_time);
7406 // get the hours, minutes and seconds
7407 hours = (int)(mtime / 3600.0f);
7409 mtime -= (3600.0f * (float)hours);
7411 seconds = (int)mtime%60;
7412 minutes = (int)mtime/60;
7415 SDL_snprintf(time_str, time_str_len, "%d:%02d:%02d", hours, minutes, seconds);
7417 SDL_snprintf(time_str, time_str_len, "%d:%02d", minutes, seconds);
7421 // Stuff version string in *str.
7422 void get_version_string(char *str, const int str_len)
7425 if ( FS_VERSION_BUILD == 0 ) {
7426 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7428 SDL_snprintf(str, str_len, "v%d.%02d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7431 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7432 SDL_strlcat(str, " D", str_len);
7433 #elif defined (OEM_BUILD)
7434 SDL_strlcat(str, " (OEM)", str_len);
7440 char myname[_MAX_PATH];
7441 int namelen, major, minor, build, waste;
7442 unsigned int buf_size;
7448 // Find my EXE file name
7449 hMod = GetModuleHandle(NULL);
7450 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7452 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7453 infop = (char *)malloc(version_size);
7454 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7456 // get the product version
7457 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7458 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7460 sprintf(str,"Dv%d.%02d",major, minor);
7462 sprintf(str,"v%d.%02d",major, minor);
7467 void get_version_string_short(char *str, const int str_len)
7469 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7472 // ----------------------------------------------------------------
7474 // OEM UPSELL SCREENS BEGIN
7476 // ----------------------------------------------------------------
7477 #if defined(OEM_BUILD)
7479 #define NUM_OEM_UPSELL_SCREENS 3
7480 #define OEM_UPSELL_SCREEN_DELAY 10000
7482 static int Oem_upsell_bitmaps_loaded = 0;
7483 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7484 static int Oem_upsell_screen_number = 0;
7485 static int Oem_upsell_show_next_bitmap_time;
7488 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7501 static int Oem_normal_cursor = -1;
7502 static int Oem_web_cursor = -1;
7503 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7504 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7506 void oem_upsell_next_screen()
7508 Oem_upsell_screen_number++;
7509 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7510 // extra long delay, mouse shown on last upsell
7511 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7515 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7519 void oem_upsell_load_bitmaps()
7523 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7524 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7528 void oem_upsell_unload_bitmaps()
7532 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7533 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7534 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7539 Oem_upsell_bitmaps_loaded = 0;
7542 // clickable hotspot on 3rd OEM upsell screen
7543 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7545 28, 350, 287, 96 // x, y, w, h
7548 45, 561, 460, 152 // x, y, w, h
7552 void oem_upsell_show_screens()
7554 int current_time, k;
7557 if ( !Oem_upsell_bitmaps_loaded ) {
7558 oem_upsell_load_bitmaps();
7559 Oem_upsell_bitmaps_loaded = 1;
7562 // may use upsell screens more than once
7563 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7564 Oem_upsell_screen_number = 0;
7570 int nframes; // used to pass, not really needed (should be 1)
7571 Oem_normal_cursor = gr_get_cursor_bitmap();
7572 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7573 SDL_assert(Oem_web_cursor >= 0);
7574 if (Oem_web_cursor < 0) {
7575 Oem_web_cursor = Oem_normal_cursor;
7580 //oem_reset_trailer_timer();
7582 current_time = timer_get_milliseconds();
7587 // advance screen on keypress or timeout
7588 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7589 oem_upsell_next_screen();
7592 // check if we are done
7593 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7594 Oem_upsell_screen_number--;
7597 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7602 // show me the upsell
7603 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7604 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7608 // if this is the 3rd upsell, make it clickable, d00d
7609 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7611 int button_state = mouse_get_pos(&mx, &my);
7612 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])
7613 && (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]) )
7616 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7619 if (button_state & MOUSE_LEFT_BUTTON) {
7621 multi_pxo_url(OEM_UPSELL_URL);
7625 // switch cursor back to normal one
7626 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7631 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7641 oem_upsell_unload_bitmaps();
7643 // switch cursor back to normal one
7644 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7648 #endif // defined(OEM_BUILD)
7649 // ----------------------------------------------------------------
7651 // OEM UPSELL SCREENS END
7653 // ----------------------------------------------------------------
7657 // ----------------------------------------------------------------
7659 // DEMO UPSELL SCREENS BEGIN
7661 // ----------------------------------------------------------------
7663 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7666 #define NUM_DEMO_UPSELL_SCREENS 2
7668 #define NUM_DEMO_UPSELL_SCREENS 4
7670 #define DEMO_UPSELL_SCREEN_DELAY 3000
7672 static int Demo_upsell_bitmaps_loaded = 0;
7673 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7674 static int Demo_upsell_screen_number = 0;
7675 static int Demo_upsell_show_next_bitmap_time;
7678 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7704 void demo_upsell_next_screen()
7706 Demo_upsell_screen_number++;
7707 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7708 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7710 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7714 void demo_upsell_load_bitmaps()
7718 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7719 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7723 void demo_upsell_unload_bitmaps()
7727 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7728 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7729 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7734 Demo_upsell_bitmaps_loaded = 0;
7737 void demo_upsell_show_screens()
7739 int current_time, k;
7742 if ( !Demo_upsell_bitmaps_loaded ) {
7743 demo_upsell_load_bitmaps();
7744 Demo_upsell_bitmaps_loaded = 1;
7747 // may use upsell screens more than once
7748 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7749 Demo_upsell_screen_number = 0;
7756 demo_reset_trailer_timer();
7758 current_time = timer_get_milliseconds();
7765 // don't time out, wait for keypress
7767 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7768 demo_upsell_next_screen();
7773 demo_upsell_next_screen();
7776 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7777 Demo_upsell_screen_number--;
7780 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7785 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7786 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7791 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7801 demo_upsell_unload_bitmaps();
7806 // ----------------------------------------------------------------
7808 // DEMO UPSELL SCREENS END
7810 // ----------------------------------------------------------------
7813 // ----------------------------------------------------------------
7815 // Subspace Ambient Sound START
7817 // ----------------------------------------------------------------
7819 static int Subspace_ambient_left_channel = -1;
7820 static int Subspace_ambient_right_channel = -1;
7823 void game_start_subspace_ambient_sound()
7825 if ( Subspace_ambient_left_channel < 0 ) {
7826 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7829 if ( Subspace_ambient_right_channel < 0 ) {
7830 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7834 void game_stop_subspace_ambient_sound()
7836 if ( Subspace_ambient_left_channel >= 0 ) {
7837 snd_stop(Subspace_ambient_left_channel);
7838 Subspace_ambient_left_channel = -1;
7841 if ( Subspace_ambient_right_channel >= 0 ) {
7842 snd_stop(Subspace_ambient_right_channel);
7843 Subspace_ambient_right_channel = -1;
7847 // ----------------------------------------------------------------
7849 // Subspace Ambient Sound END
7851 // ----------------------------------------------------------------
7853 // ----------------------------------------------------------------
7855 // Language Autodetection stuff
7858 // this layout order must match Lcl_languages in localize.cpp in order for the
7859 // correct language to be detected
7860 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
7862 1366105450, // English
7864 589986744, // English
7866 -1132430286, // German
7868 -1131728960, // Polish
7871 // default setting is "-1" to use config file with English as fall back
7872 // DO NOT change the default setting here or something uncouth might happen
7873 // in the localization code
7879 // try and open the file to verify
7880 CFILE *detect = cfopen("font01.vf", "rb");
7882 // will use default setting if something went wrong
7887 // get the long checksum of the file
7889 cfseek(detect, 0, SEEK_SET);
7890 cf_chksum_long(detect, &file_checksum);
7894 // now compare the checksum/filesize against known #'s
7895 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
7896 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
7901 // notify if a match was not found, include detected checksum
7902 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
7903 printf("Using default language...\n\n");
7909 // End Auto Lang stuff
7911 // ----------------------------------------------------------------
7913 // ----------------------------------------------------------------
7914 // SHIPS TBL VERIFICATION STUFF
7917 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
7918 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
7919 #define NUM_SHIPS_TBL_CHECKSUMS 3
7921 #define NUM_SHIPS_TBL_CHECKSUMS 1
7925 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7926 1696074201, // FS2 demo
7929 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7930 1603375034, // FS1 DEMO
7933 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7934 -129679197, // FS1 Full 1.06 (US)
7935 7762567, // FS1 SilentThreat
7936 1555372475 // FS1 Full 1.06 (German)
7940 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7941 -463907578, // US - beta 1
7942 1696074201, // FS2 demo
7945 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7946 // -1022810006, // 1.0 FULL
7947 -1254285366 // 1.2 FULL (German)
7951 void verify_ships_tbl()
7955 Game_ships_tbl_valid = 1;
7961 // detect if the packfile exists
7962 CFILE *detect = cfopen("ships.tbl", "rb");
7963 Game_ships_tbl_valid = 0;
7967 Game_ships_tbl_valid = 0;
7971 // get the long checksum of the file
7973 cfseek(detect, 0, SEEK_SET);
7974 cf_chksum_long(detect, &file_checksum);
7978 // now compare the checksum/filesize against known #'s
7979 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
7980 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
7981 Game_ships_tbl_valid = 1;
7988 DCF(shipspew, "display the checksum for the current ships.tbl")
7991 CFILE *detect = cfopen("ships.tbl", "rb");
7992 // get the long checksum of the file
7994 cfseek(detect, 0, SEEK_SET);
7995 cf_chksum_long(detect, &file_checksum);
7998 dc_printf("%d", file_checksum);
8001 // ----------------------------------------------------------------
8002 // WEAPONS TBL VERIFICATION STUFF
8005 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8006 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8007 #define NUM_WEAPONS_TBL_CHECKSUMS 3
8009 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8013 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8014 -266420030, // demo 1
8017 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8018 -1246928725, // FS1 DEMO
8021 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8022 -834598107, // FS1 1.06 Full (US)
8023 -1652231417, // FS1 SilentThreat
8024 720209793 // FS1 1.06 Full (German)
8028 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8029 141718090, // US - beta 1
8030 -266420030, // demo 1
8033 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8034 // 399297860, // 1.0 FULL
8035 -553984927 // 1.2 FULL (german)
8039 void verify_weapons_tbl()
8043 Game_weapons_tbl_valid = 1;
8049 // detect if the packfile exists
8050 CFILE *detect = cfopen("weapons.tbl", "rb");
8051 Game_weapons_tbl_valid = 0;
8055 Game_weapons_tbl_valid = 0;
8059 // get the long checksum of the file
8061 cfseek(detect, 0, SEEK_SET);
8062 cf_chksum_long(detect, &file_checksum);
8066 // now compare the checksum/filesize against known #'s
8067 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8068 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8069 Game_weapons_tbl_valid = 1;
8076 DCF(wepspew, "display the checksum for the current weapons.tbl")
8079 CFILE *detect = cfopen("weapons.tbl", "rb");
8080 // get the long checksum of the file
8082 cfseek(detect, 0, SEEK_SET);
8083 cf_chksum_long(detect, &file_checksum);
8086 dc_printf("%d", file_checksum);
8089 // if the game is running using hacked data
8090 int game_hacked_data()
8093 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8101 void display_title_screen()
8103 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
8104 ///int title_bitmap;
8107 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8108 if (title_bitmap == -1) {
8113 gr_set_bitmap(title_bitmap);
8121 bm_unload(title_bitmap);
8122 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
8125 // return true if the game is running with "low memory", which is less than 48MB
8126 bool game_using_low_mem()
8128 if (Use_low_mem == 0) {