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.
572 #include "systemvars.h"
577 #include "starfield.h"
578 #include "lighting.h"
583 #include "fireballs.h"
587 #include "floating.h"
588 #include "gamesequence.h"
590 #include "optionsmenu.h"
591 #include "playermenu.h"
592 #include "trainingmenu.h"
593 #include "techmenu.h"
596 #include "hudmessage.h"
598 #include "missiongoals.h"
599 #include "missionparse.h"
604 #include "multiutil.h"
605 #include "multimsgs.h"
609 #include "freespace.h"
610 #include "managepilot.h"
612 #include "contexthelp.h"
615 #include "missionbrief.h"
616 #include "missiondebrief.h"
618 #include "missionshipchoice.h"
620 #include "hudconfig.h"
621 #include "controlsconfig.h"
622 #include "missionmessage.h"
623 #include "missiontraining.h"
625 #include "hudtarget.h"
627 #include "eventmusic.h"
628 #include "animplay.h"
629 #include "missionweaponchoice.h"
630 #include "missionlog.h"
631 #include "audiostr.h"
633 #include "missioncampaign.h"
635 #include "missionhotkey.h"
636 #include "objectsnd.h"
637 #include "cmeasure.h"
639 #include "linklist.h"
640 #include "shockwave.h"
641 #include "afterburner.h"
646 #include "stand_gui.h"
647 #include "pcxutils.h"
648 #include "hudtargetbox.h"
649 #include "multi_xfer.h"
650 #include "hudescort.h"
651 #include "multiutil.h"
654 #include "multiteamselect.h"
656 #include "readyroom.h"
657 #include "mainhallmenu.h"
658 #include "multilag.h"
660 #include "particle.h"
662 #include "multi_ingame.h"
663 #include "snazzyui.h"
664 #include "asteroid.h"
665 #include "popupdead.h"
666 #include "multi_voice.h"
667 #include "missioncmdbrief.h"
668 #include "redalert.h"
669 #include "gameplayhelp.h"
670 #include "multilag.h"
671 #include "staticrand.h"
672 #include "multi_pmsg.h"
673 #include "levelpaging.h"
674 #include "observer.h"
675 #include "multi_pause.h"
676 #include "multi_endgame.h"
677 #include "cutscenes.h"
678 #include "multi_respawn.h"
680 #include "multi_obj.h"
681 #include "multi_log.h"
683 #include "localize.h"
684 #include "osregistry.h"
685 #include "barracks.h"
686 #include "missionpause.h"
688 #include "alphacolors.h"
689 #include "objcollide.h"
692 #include "neblightning.h"
693 #include "shipcontrails.h"
696 #include "multi_dogfight.h"
697 #include "multi_rate.h"
698 #include "muzzleflash.h"
702 #include "mainhalltemp.h"
703 #include "exceptionhandler.h"
704 #include "supernova.h"
705 #include "hudshield.h"
706 // #include "names.h"
708 #include "missionloopbrief.h"
712 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
718 // 1.00.04 5/26/98 MWA -- going final (12 pm)
719 // 1.00.03 5/26/98 MWA -- going final (3 am)
720 // 1.00.02 5/25/98 MWA -- going final
721 // 1.00.01 5/25/98 MWA -- going final
722 // 0.90 5/21/98 MWA -- getting ready for final.
723 // 0.10 4/9/98. Set by MK.
725 // Demo version: (obsolete since DEMO codebase split from tree)
726 // 0.03 4/10/98 AL. Interplay rev
727 // 0.02 4/8/98 MK. Increased when this system was modified.
728 // 0.01 4/7/98? AL. First release to Interplay QA.
731 // 1.00 5/28/98 AL. First release to Interplay QA.
733 void game_level_init(int seed = -1);
734 void game_post_level_init();
735 void game_do_frame();
736 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
737 void game_reset_time();
738 void game_show_framerate(); // draws framerate in lower right corner
740 int Game_no_clear = 0;
742 int Pofview_running = 0;
743 int Nebedit_running = 0;
744 int Fonttool_running = 0;
746 typedef struct big_expl_flash {
747 float max_flash_intensity; // max intensity
748 float cur_flash_intensity; // cur intensity
749 int flash_start; // start time
752 #define FRAME_FILTER 16
754 #define DEFAULT_SKILL_LEVEL 1
755 int Game_skill_level = DEFAULT_SKILL_LEVEL;
757 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
758 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
760 #define EXE_FNAME ("fs2.exe")
761 #define LAUNCHER_FNAME ("freespace2.exe")
764 // JAS: Code for warphole camera.
765 // Needs to be cleaned up.
766 vector Camera_pos = ZERO_VECTOR;
767 vector Camera_velocity = ZERO_VECTOR;
768 vector Camera_desired_velocity = ZERO_VECTOR;
769 matrix Camera_orient = IDENTITY_MATRIX;
770 float Camera_damping = 1.0f;
771 float Camera_time = 0.0f;
772 float Warpout_time = 0.0f;
773 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
774 int Warpout_sound = -1;
776 int Use_joy_mouse = 0;
777 int Use_palette_flash = 1;
778 int Show_area_effect = 0;
779 object *Last_view_target = NULL;
781 int dogfight_blown = 0;
784 float frametimes[FRAME_FILTER];
785 float frametotal = 0.0f;
789 int Show_framerate = 0;
791 int Show_framerate = 1;
794 int Framerate_cap = 120;
797 int Show_target_debug_info = 0;
798 int Show_target_weapons = 0;
802 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
805 int Debug_octant = -1;
807 fix Game_time_compression = F1_0;
809 // if the ships.tbl the player has is valid
810 int Game_ships_tbl_valid = 0;
812 // if the weapons.tbl the player has is valid
813 int Game_weapons_tbl_valid = 0;
817 extern int Player_attacking_enabled;
821 int Pre_player_entry;
823 int Fred_running = 0;
824 char Game_current_mission_filename[MAX_FILENAME_LEN];
825 int game_single_step = 0;
826 int last_single_step=0;
828 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
829 extern int MSG_WINDOW_Y_START;
830 extern int MSG_WINDOW_HEIGHT;
832 int game_zbuffer = 1;
833 //static int Game_music_paused;
834 static int Game_paused;
838 #define EXPIRE_BAD_CHECKSUM 1
839 #define EXPIRE_BAD_TIME 2
841 extern void ssm_init();
842 extern void ssm_level_init();
843 extern void ssm_process();
845 // static variable to contain the time this version was built
846 // commented out for now until
847 // I figure out how to get the username into the file
848 //static char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
850 // defines and variables used for dumping frame for making trailers.
852 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
853 int Debug_dump_trigger = 0;
854 int Debug_dump_frame_count;
855 int Debug_dump_frame_num = 0;
856 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
859 // amount of time to wait after the player has died before we display the death died popup
860 #define PLAYER_DIED_POPUP_WAIT 2500
861 int Player_died_popup_wait = -1;
862 time_t Player_multi_died_check = -1;
864 // builtin mission list stuff
866 int Game_builtin_mission_count = 6;
867 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
868 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
869 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
870 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
871 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
872 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
873 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
875 #elif defined(FS1_DEMO)
876 int Game_builtin_mission_count = 5;
877 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
878 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
879 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
880 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
881 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
882 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
884 #elif defined(PD_BUILD)
885 int Game_builtin_mission_count = 4;
886 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
887 { "sm1-01.fs2", (FSB_FROM_VOLITION) },
888 { "sm1-05.fs2", (FSB_FROM_VOLITION) },
889 { "sm1-01", (FSB_FROM_VOLITION) },
890 { "sm1-05", (FSB_FROM_VOLITION) },
892 #elif defined(MULTIPLAYER_BETA)
893 int Game_builtin_mission_count = 17;
894 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
896 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
897 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
898 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
899 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
900 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
901 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
902 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
903 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
904 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
905 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
906 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
907 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
908 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
909 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
910 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
911 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
912 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
914 #elif defined(OEM_BUILD)
915 int Game_builtin_mission_count = 17;
916 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
917 // oem version - act 1 only
918 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
921 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
922 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
923 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
924 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
925 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
926 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
927 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
928 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
929 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
930 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
931 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
932 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
933 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
934 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
935 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
936 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) }
938 #elif defined(MAKE_FS1)
939 int Game_builtin_mission_count = 125;
940 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
941 // single player campaign
942 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
945 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
946 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
947 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
948 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
949 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
950 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
951 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
952 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
953 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
954 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
957 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
958 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
959 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
960 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
961 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
962 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
963 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
964 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
965 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
966 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
969 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
970 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
971 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
972 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
973 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
974 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
975 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
976 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
977 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
980 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
981 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
982 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
985 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
986 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
987 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
988 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
989 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
992 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
993 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
995 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
996 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
997 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
998 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
999 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1000 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1001 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1002 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1003 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1004 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1005 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1006 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1007 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1008 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1009 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1010 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1011 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1012 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1013 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI) },
1015 // SilentThreat missions
1016 // Main SilentThreat campaign
1017 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE) },
1019 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1020 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1021 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1022 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1023 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1024 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1025 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1026 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1027 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1028 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1029 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1030 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN) },
1032 // SilentThreat Part 1 - multi-coop
1033 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1035 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1036 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1037 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1039 // SilentThreat Part 2 - multi-coop
1040 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1042 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1043 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1044 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1046 // SilentThreat Part 3 - multi-coop
1047 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1049 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1050 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1051 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1053 // SilentThreat Part 4 - multi-coop
1054 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1056 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1057 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1058 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN) },
1060 // multiplayer missions
1061 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1062 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1063 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1064 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI) },
1065 // user supplied missions
1066 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1067 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1068 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1069 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1070 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1071 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1072 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1073 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1074 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1075 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1076 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1077 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1078 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1079 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1080 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1081 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1082 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1083 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1084 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1085 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1086 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1087 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1088 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1089 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1090 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1091 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1092 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1093 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1094 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1095 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1096 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1097 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI) },
1100 int Game_builtin_mission_count = 92;
1101 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1102 // single player campaign
1103 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE) },
1106 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1107 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1108 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1109 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1110 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1111 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1112 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1113 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1114 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1115 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1116 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1117 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1118 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1119 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1120 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1121 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1122 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1123 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1124 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1127 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1128 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1129 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1130 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1131 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1132 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1133 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1134 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1135 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1136 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1139 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1140 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1141 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1142 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1143 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1144 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1145 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1146 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1147 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1148 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1149 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1150 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN) },
1152 // multiplayer missions
1155 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1156 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1157 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1160 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1161 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1162 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1163 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1166 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1167 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1168 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1169 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1170 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1171 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1172 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1173 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1174 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1175 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1176 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1177 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1178 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1179 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1180 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1181 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1182 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1183 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1184 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1185 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1186 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1187 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1188 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1189 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1190 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1191 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1192 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1193 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1196 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1197 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1198 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1199 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1200 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1201 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1202 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1203 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1204 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1205 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI) },
1208 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE) },
1209 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1210 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1211 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1212 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN) },
1217 // Internal function prototypes
1218 void game_maybe_draw_mouse(float frametime);
1219 void init_animating_pointer();
1220 void load_animating_pointer(const char *filename, int dx, int dy);
1221 void unload_animating_pointer();
1222 void game_do_training_checks();
1223 void game_shutdown(void);
1224 void game_show_event_debug(float frametime);
1225 void game_event_debug_init();
1227 void demo_upsell_show_screens();
1228 void game_start_subspace_ambient_sound();
1229 void game_stop_subspace_ambient_sound();
1230 void verify_ships_tbl();
1231 void verify_weapons_tbl();
1232 void display_title_screen();
1234 // loading background filenames
1235 static const char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1236 "LoadingBG", // GR_640
1237 "2_LoadingBG" // GR_1024
1241 static const char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1242 "Loading.ani", // GR_640
1243 "2_Loading.ani" // GR_1024
1246 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1247 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1255 #elif defined(OEM_BUILD)
1256 static const char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1265 // How much RAM is on this machine. Set in WinMain
1266 static int Freespace_total_ram = 0;
1269 float Game_flash_red = 0.0f;
1270 float Game_flash_green = 0.0f;
1271 float Game_flash_blue = 0.0f;
1272 float Sun_spot = 0.0f;
1273 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1275 // game shudder stuff (in ms)
1276 int Game_shudder_time = -1;
1277 int Game_shudder_total = 0;
1278 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1281 sound_env Game_sound_env;
1282 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1283 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1285 int Game_sound_env_update_timestamp;
1287 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1290 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1292 fs_builtin_mission *game_find_builtin_mission(const char *filename)
1296 // look through all existing builtin missions
1297 for(idx=0; idx<Game_builtin_mission_count; idx++){
1298 if(!SDL_strcasecmp(Game_builtin_mission_list[idx].filename, filename)){
1299 return &Game_builtin_mission_list[idx];
1307 int game_get_default_skill_level()
1309 return DEFAULT_SKILL_LEVEL;
1313 void game_flash_reset()
1315 Game_flash_red = 0.0f;
1316 Game_flash_green = 0.0f;
1317 Game_flash_blue = 0.0f;
1319 Big_expl_flash.max_flash_intensity = 0.0f;
1320 Big_expl_flash.cur_flash_intensity = 0.0f;
1321 Big_expl_flash.flash_start = 0;
1324 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1325 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1327 void game_framerate_check_init()
1329 // zero critical time
1330 Gf_critical_time = 0.0f;
1333 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1334 Gf_critical = 15.0f;
1336 Gf_critical = 25.0f;
1340 extern float Framerate;
1341 void game_framerate_check()
1345 // if the current framerate is above the critical level, add frametime
1346 if(Framerate >= Gf_critical){
1347 Gf_critical_time += flFrametime;
1350 if(!Show_framerate){
1354 // display if we're above the critical framerate
1355 if(Framerate < Gf_critical){
1356 gr_set_color_fast(&Color_bright_red);
1357 gr_string(200, y_start, "Framerate warning");
1362 // display our current pct of good frametime
1363 if(f2fl(Missiontime) >= 0.0f){
1364 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1367 gr_set_color_fast(&Color_bright_green);
1369 gr_set_color_fast(&Color_bright_red);
1372 gr_printf(200, y_start, "%d%%", (int)pct);
1377 // Adds a flash effect. These can be positive or negative.
1378 // The range will get capped at around -1 to 1, so stick
1379 // with a range like that.
1380 void game_flash( float r, float g, float b )
1382 Game_flash_red += r;
1383 Game_flash_green += g;
1384 Game_flash_blue += b;
1386 if ( Game_flash_red < -1.0f ) {
1387 Game_flash_red = -1.0f;
1388 } else if ( Game_flash_red > 1.0f ) {
1389 Game_flash_red = 1.0f;
1392 if ( Game_flash_green < -1.0f ) {
1393 Game_flash_green = -1.0f;
1394 } else if ( Game_flash_green > 1.0f ) {
1395 Game_flash_green = 1.0f;
1398 if ( Game_flash_blue < -1.0f ) {
1399 Game_flash_blue = -1.0f;
1400 } else if ( Game_flash_blue > 1.0f ) {
1401 Game_flash_blue = 1.0f;
1406 // Adds a flash for Big Ship explosions
1407 // cap range from 0 to 1
1408 void big_explosion_flash(float flash)
1410 Big_expl_flash.flash_start = timestamp(1);
1414 } else if (flash < 0.0f) {
1418 Big_expl_flash.max_flash_intensity = flash;
1419 Big_expl_flash.cur_flash_intensity = 0.0f;
1422 // Amount to diminish palette towards normal, per second.
1423 #define DIMINISH_RATE 0.75f
1424 #define SUN_DIMINISH_RATE 6.00f
1428 float sn_glare_scale = 1.7f;
1431 dc_get_arg(ARG_FLOAT);
1432 sn_glare_scale = Dc_arg_float;
1435 float Supernova_last_glare = 0.0f;
1436 void game_sunspot_process(float frametime)
1440 float Sun_spot_goal = 0.0f;
1443 sn_stage = supernova_active();
1445 // sunspot differently based on supernova stage
1447 // approaching. player still in control
1450 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1453 light_get_global_dir(&light_dir, 0);
1455 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1458 // scale it some more
1459 dot = dot * (0.5f + (pct * 0.5f));
1462 Sun_spot_goal += (dot * sn_glare_scale);
1465 // draw the sun glow
1466 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1467 // draw the glow for this sun
1468 stars_draw_sun_glow(0);
1471 Supernova_last_glare = Sun_spot_goal;
1474 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1477 Sun_spot_goal = 0.9f;
1478 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1480 if(Sun_spot_goal > 1.0f){
1481 Sun_spot_goal = 1.0f;
1484 Sun_spot_goal *= sn_glare_scale;
1485 Supernova_last_glare = Sun_spot_goal;
1488 // fade to white. display dead popup
1491 Supernova_last_glare += (2.0f * flFrametime);
1492 if(Supernova_last_glare > 2.0f){
1493 Supernova_last_glare = 2.0f;
1496 Sun_spot_goal = Supernova_last_glare;
1503 // check sunspots for all suns
1504 n_lights = light_get_global_count();
1507 for(idx=0; idx<n_lights; idx++){
1508 //(vector *eye_pos, matrix *eye_orient)
1509 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1512 light_get_global_dir(&light_dir, idx);
1514 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1516 Sun_spot_goal += (float)pow(dot,85.0f);
1518 // draw the glow for this sun
1519 stars_draw_sun_glow(idx);
1521 Sun_spot_goal = 0.0f;
1527 Sun_spot_goal = 0.0f;
1531 float dec_amount = frametime*SUN_DIMINISH_RATE;
1533 if ( Sun_spot < Sun_spot_goal ) {
1534 Sun_spot += dec_amount;
1535 if ( Sun_spot > Sun_spot_goal ) {
1536 Sun_spot = Sun_spot_goal;
1538 } else if ( Sun_spot > Sun_spot_goal ) {
1539 Sun_spot -= dec_amount;
1540 if ( Sun_spot < Sun_spot_goal ) {
1541 Sun_spot = Sun_spot_goal;
1547 // Call once a frame to diminish the
1548 // flash effect to 0.
1549 void game_flash_diminish(float frametime)
1551 float dec_amount = frametime*DIMINISH_RATE;
1553 if ( Game_flash_red > 0.0f ) {
1554 Game_flash_red -= dec_amount;
1555 if ( Game_flash_red < 0.0f )
1556 Game_flash_red = 0.0f;
1558 Game_flash_red += dec_amount;
1559 if ( Game_flash_red > 0.0f )
1560 Game_flash_red = 0.0f;
1563 if ( Game_flash_green > 0.0f ) {
1564 Game_flash_green -= dec_amount;
1565 if ( Game_flash_green < 0.0f )
1566 Game_flash_green = 0.0f;
1568 Game_flash_green += dec_amount;
1569 if ( Game_flash_green > 0.0f )
1570 Game_flash_green = 0.0f;
1573 if ( Game_flash_blue > 0.0f ) {
1574 Game_flash_blue -= dec_amount;
1575 if ( Game_flash_blue < 0.0f )
1576 Game_flash_blue = 0.0f;
1578 Game_flash_blue += dec_amount;
1579 if ( Game_flash_blue > 0.0f )
1580 Game_flash_blue = 0.0f;
1583 // update big_explosion_cur_flash
1584 #define TIME_UP 1500
1585 #define TIME_DOWN 2500
1586 int duration = TIME_UP + TIME_DOWN;
1587 int time = timestamp_until(Big_expl_flash.flash_start);
1588 if (time > -duration) {
1590 if (time < TIME_UP) {
1591 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1594 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1598 if ( Use_palette_flash ) {
1600 // static int or=0, og=0, ob=0;
1602 // Change the 200 to change the color range of colors.
1603 r = fl2i( Game_flash_red*128.0f );
1604 g = fl2i( Game_flash_green*128.0f );
1605 b = fl2i( Game_flash_blue*128.0f );
1607 if ( Sun_spot > 0.0f ) {
1608 r += fl2i(Sun_spot*128.0f);
1609 g += fl2i(Sun_spot*128.0f);
1610 b += fl2i(Sun_spot*128.0f);
1613 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1614 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1615 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1616 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1619 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1620 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1621 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1623 if ( (r!=0) || (g!=0) || (b!=0) ) {
1624 gr_flash( r, g, b );
1626 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1637 void game_level_close()
1639 // De-Initialize the game subsystems
1640 event_music_level_close();
1641 game_stop_looped_sounds();
1643 obj_snd_level_close(); // uninit object-linked persistant sounds
1644 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1645 anim_level_close(); // stop and clean up any anim instances
1646 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1647 shockwave_level_close();
1648 fireball_level_close();
1650 mission_event_shutdown();
1651 asteroid_level_close();
1652 flak_level_close(); // unload flak stuff
1653 neb2_level_close(); // shutdown gaseous nebula stuff
1656 mflash_level_close();
1657 mission_brief_common_reset(); // close out parsed briefing/mission stuff
1659 audiostream_unpause_all();
1664 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1665 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1666 void game_level_init(int seed)
1668 // seed the random number generator
1670 // if no seed was passed, seed the generator either from the time value, or from the
1671 // netgame security flags -- ensures that all players in multiplayer game will have the
1672 // same randon number sequence (with static rand functions)
1673 if ( Game_mode & GM_NORMAL ) {
1674 Game_level_seed = (int)time(NULL);
1676 Game_level_seed = Netgame.security;
1679 // mwa 9/17/98 -- maybe this assert isn't needed????
1680 SDL_assert( !(Game_mode & GM_MULTIPLAYER) );
1681 Game_level_seed = seed;
1683 srand( Game_level_seed );
1685 // semirand function needs to get re-initted every time in multiplayer
1686 if ( Game_mode & GM_MULTIPLAYER ){
1692 Key_normal_game = (Game_mode & GM_NORMAL);
1695 Game_shudder_time = -1;
1697 // Initialize the game subsystems
1698 // timestamp_reset(); // Must be inited before everything else
1700 game_reset_time(); // resets time, and resets saved time too
1702 obj_init(); // Must be inited before the other systems
1703 model_free_all(); // Free all existing models
1704 mission_brief_common_init(); // Free all existing briefing/debriefing text
1705 weapon_level_init();
1706 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1708 player_level_init();
1709 shipfx_flash_init(); // Init the ship gun flash system.
1710 game_flash_reset(); // Reset the flash effect
1711 particle_init(); // Reset the particle system
1715 shield_hit_init(); // Initialize system for showing shield hits
1716 radar_mission_init();
1717 mission_init_goals();
1720 obj_snd_level_init(); // init object-linked persistant sounds
1722 shockwave_level_init();
1723 afterburner_level_init();
1724 scoring_level_init( &Player->stats );
1726 asteroid_level_init();
1727 control_config_clear_used_status();
1728 collide_ship_ship_sounds_init();
1730 Pre_player_entry = 1; // Means the player has not yet entered.
1731 Entry_delay_time = 0; // Could get overwritten in mission read.
1732 fireball_preload(); // page in warphole bitmaps
1734 flak_level_init(); // initialize flak - bitmaps, etc
1735 ct_level_init(); // initialize ships contrails, etc
1736 awacs_level_init(); // initialize AWACS
1737 beam_level_init(); // initialize beam weapons
1738 mflash_level_init();
1740 supernova_level_init();
1742 // multiplayer dogfight hack
1745 shipfx_engine_wash_level_init();
1749 Last_view_target = NULL;
1754 // campaign wasn't ended
1755 Campaign_ended_in_mission = 0;
1758 // called when a mission is over -- does server specific stuff.
1759 void freespace_stop_mission()
1762 Game_mode &= ~GM_IN_MISSION;
1765 // called at frame interval to process networking stuff
1766 void game_do_networking()
1768 SDL_assert( Net_player != NULL );
1769 if (!(Game_mode & GM_MULTIPLAYER)){
1773 // see if this player should be reading/writing data. Bit is set when at join
1774 // screen onward until quits back to main menu.
1775 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1779 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1782 multi_pause_do_frame();
1787 // Loads the best palette for this level, based
1788 // on nebula color and hud color. You could just call palette_load_table with
1789 // the appropriate filename, but who wants to do that.
1790 void game_load_palette()
1792 char palette_filename[1024];
1794 // We only use 3 hud colors right now
1796 SDL_assert( HUD_config.main_color >= 0 );
1797 SDL_assert( HUD_config.main_color <= 2 );
1800 SDL_assert( Mission_palette >= 0 );
1801 SDL_assert( Mission_palette <= 98 );
1804 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1805 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), sizeof(palette_filename) );
1807 SDL_snprintf( palette_filename, sizeof(palette_filename), NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1810 mprintf(( "Loading palette %s\n", palette_filename ));
1812 palette_load_table(palette_filename);
1814 SDL_strlcpy( palette_filename, NOX("gamepalette-subspace"), sizeof(palette_filename) );
1816 mprintf(( "Loading palette %s\n", palette_filename ));
1820 void game_post_level_init()
1822 // Stuff which gets called after mission is loaded. Because player isn't created until
1823 // after mission loads, some things must get initted after the level loads
1825 model_level_post_init();
1828 hud_setup_escort_list();
1829 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1835 game_event_debug_init();
1838 training_mission_init();
1839 asteroid_create_all();
1841 game_framerate_check_init();
1845 // An estimate as to how high the count passed to game_loading_callback will go.
1846 // This is just a guess, it seems to always be about the same. The count is
1847 // proportional to the code being executed, not the time, so this works good
1848 // for a bar, assuming the code does about the same thing each time you
1849 // load a level. You can find this value by looking at the return value
1850 // of game_busy_callback(NULL), which I conveniently print out to the
1851 // debug output window with the '=== ENDING LOAD ==' stuff.
1852 //#define COUNT_ESTIMATE 3706
1853 #define COUNT_ESTIMATE 1111
1855 int Game_loading_callback_inited = 0;
1857 int Game_loading_background = -1;
1858 anim * Game_loading_ani = NULL;
1859 anim_instance *Game_loading_ani_instance;
1860 int Game_loading_frame=-1;
1862 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1864 #if defined(FS1_DEMO)
1866 #elif defined(MAKE_FS1)
1877 // This gets called 10x per second and count is the number of times
1878 // game_busy() has been called since the current callback function
1880 void game_loading_callback(int count)
1882 game_do_networking();
1884 SDL_assert( Game_loading_callback_inited==1 );
1885 SDL_assert( Game_loading_ani != NULL );
1887 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1888 if ( framenum > Game_loading_ani->total_frames-1 ) {
1889 framenum = Game_loading_ani->total_frames-1;
1890 } else if ( framenum < 0 ) {
1895 while ( Game_loading_frame < framenum ) {
1896 Game_loading_frame++;
1897 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1901 if ( cbitmap > -1 ) {
1902 if ( Game_loading_background > -1 ) {
1903 gr_set_bitmap( Game_loading_background, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1907 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1908 gr_set_bitmap( cbitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1909 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1911 bm_release(cbitmap);
1917 void game_loading_callback_init()
1919 SDL_assert( Game_loading_callback_inited==0 );
1921 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1923 common_set_interface_palette("InterfacePalette"); // set the interface palette
1927 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1928 SDL_assert( Game_loading_ani != NULL );
1929 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1930 SDL_assert( Game_loading_ani_instance != NULL );
1931 Game_loading_frame = -1;
1933 Game_loading_callback_inited = 1;
1935 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1940 void game_loading_callback_close()
1942 SDL_assert( Game_loading_callback_inited==1 );
1944 // Make sure bar shows all the way over.
1945 game_loading_callback(COUNT_ESTIMATE);
1947 int real_count = game_busy_callback( NULL );
1950 Game_loading_callback_inited = 0;
1953 mprintf(( "=================== ENDING LOAD ================\n" ));
1954 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1955 mprintf(( "================================================\n" ));
1957 // to remove warnings in release build
1961 free_anim_instance(Game_loading_ani_instance);
1962 Game_loading_ani_instance = NULL;
1963 anim_free(Game_loading_ani);
1964 Game_loading_ani = NULL;
1966 bm_release( Game_loading_background );
1967 common_free_interface_palette(); // restore game palette
1968 Game_loading_background = -1;
1970 gr_set_font( FONT1 );
1973 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1975 void game_maybe_update_sound_environment()
1977 // do nothing for now
1980 // Assign the sound environment for the game, based on the current mission
1982 void game_assign_sound_environment()
1985 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1986 Game_sound_env.id = SND_ENV_DRUGGED;
1987 Game_sound_env.volume = 0.800f;
1988 Game_sound_env.damping = 1.188f;
1989 Game_sound_env.decay = 6.392f;
1991 } else if (Num_asteroids > 30) {
1992 Game_sound_env.id = SND_ENV_AUDITORIUM;
1993 Game_sound_env.volume = 0.603f;
1994 Game_sound_env.damping = 0.5f;
1995 Game_sound_env.decay = 4.279f;
1998 Game_sound_env = Game_default_sound_env;
2002 Game_sound_env = Game_default_sound_env;
2003 Game_sound_env_update_timestamp = timestamp(1);
2006 // function which gets called before actually entering the mission. It is broken down into a funciton
2007 // since it will get called in one place from a single player game and from another place for
2008 // a multiplayer game
2009 void freespace_mission_load_stuff()
2011 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2012 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2013 if(!(Game_mode & GM_STANDALONE_SERVER)){
2015 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2017 game_loading_callback_init();
2019 event_music_level_init(); // preloads the first 2 seconds for each event music track
2022 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2025 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2028 ship_assign_sound_all(); // assign engine sounds to ships
2029 game_assign_sound_environment(); // assign the sound environment for this mission
2032 // call function in missionparse.cpp to fixup player/ai stuff.
2033 mission_parse_fixup_players();
2036 // Load in all the bitmaps for this level
2041 game_loading_callback_close();
2043 // the only thing we need to call on the standalone for now.
2045 // call function in missionparse.cpp to fixup player/ai stuff.
2046 mission_parse_fixup_players();
2048 // Load in all the bitmaps for this level
2053 time_t load_gl_init;
2054 time_t load_mission_load;
2055 time_t load_post_level_init;
2056 time_t load_mission_stuff;
2058 // tells the server to load the mission and initialize structures
2059 int game_start_mission()
2061 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2063 load_gl_init = time(NULL);
2065 load_gl_init = time(NULL) - load_gl_init;
2067 if (Game_mode & GM_MULTIPLAYER) {
2068 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2070 // clear multiplayer stats
2071 init_multiplayer_stats();
2074 load_mission_load = time(NULL);
2075 if (mission_load()) {
2076 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2077 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2078 gameseq_post_event(GS_EVENT_MAIN_MENU);
2080 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2085 load_mission_load = time(NULL) - load_mission_load;
2087 // If this is a red alert mission in campaign mode, bash wingman status
2088 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2089 red_alert_bash_wingman_status();
2092 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2093 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2094 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2096 game_load_palette();
2100 load_post_level_init = time(NULL);
2101 game_post_level_init();
2102 load_post_level_init = time(NULL) - load_post_level_init;
2106 void Do_model_timings_test();
2107 Do_model_timings_test();
2111 load_mission_stuff = time(NULL);
2112 freespace_mission_load_stuff();
2113 load_mission_stuff = time(NULL) - load_mission_stuff;
2118 int Interface_framerate = 0;
2121 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2122 DCF_BOOL( show_framerate, Show_framerate )
2123 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2124 DCF_BOOL( show_target_weapons, Show_target_weapons )
2125 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2126 DCF_BOOL( sound, Sound_enabled )
2127 DCF_BOOL( zbuffer, game_zbuffer )
2128 DCF_BOOL( shield_system, New_shield_system )
2129 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2130 DCF_BOOL( player_attacking, Player_attacking_enabled )
2131 DCF_BOOL( show_waypoints, Show_waypoints )
2132 DCF_BOOL( show_area_effect, Show_area_effect )
2133 DCF_BOOL( show_net_stats, Show_net_stats )
2134 DCF_BOOL( log, Log_debug_output_to_file )
2135 DCF_BOOL( training_msg_method, Training_msg_method )
2136 DCF_BOOL( show_player_pos, Show_player_pos )
2137 DCF_BOOL(i_framerate, Interface_framerate )
2139 DCF(show_mem,"Toggles showing mem usage")
2142 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2143 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2144 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2145 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2151 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2153 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2154 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2158 DCF(show_cpu,"Toggles showing cpu usage")
2161 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2162 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2163 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2164 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2170 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2172 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2173 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2180 // AL 4-8-98: always allow players to display their framerate
2183 DCF_BOOL( show_framerate, Show_framerate )
2190 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2193 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2194 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2195 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2196 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2198 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" );
2199 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2201 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2204 DCF(palette_flash,"Toggles palette flash effect on/off")
2207 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2208 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2209 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2210 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2212 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2213 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2216 int Use_low_mem = 0;
2218 DCF(low_mem,"Uses low memory settings regardless of RAM")
2221 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2222 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2223 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2224 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2226 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2227 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2229 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2233 int Framerate_delay = 0;
2235 float Freespace_gamma = 1.8f;
2237 DCF(gamma,"Sets Gamma factor")
2240 dc_get_arg(ARG_FLOAT|ARG_NONE);
2241 if ( Dc_arg_type & ARG_FLOAT ) {
2242 Freespace_gamma = Dc_arg_float;
2244 dc_printf( "Gamma reset to 1.0f\n" );
2245 Freespace_gamma = 1.0f;
2247 if ( Freespace_gamma < 0.1f ) {
2248 Freespace_gamma = 0.1f;
2249 } else if ( Freespace_gamma > 5.0f ) {
2250 Freespace_gamma = 5.0f;
2252 gr_set_gamma(Freespace_gamma);
2254 char tmp_gamma_string[32];
2255 SDL_snprintf( tmp_gamma_string, sizeof(tmp_gamma_string), NOX("%.2f"), Freespace_gamma );
2256 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2260 dc_printf( "Usage: gamma <float>\n" );
2261 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2262 Dc_status = 0; // don't print status if help is printed. Too messy.
2266 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2274 Game_current_mission_filename[0] = 0;
2276 // seed the random number generator
2277 Game_init_seed = (int)time(NULL);
2278 srand( Game_init_seed );
2280 Framerate_delay = 0;
2286 extern void bm_init();
2292 // Initialize the timer before the os
2298 //Initialize the libraries
2299 s1 = timer_get_milliseconds();
2300 if ( cfile_init() ) { // initialize before calling any cfopen stuff!!!
2303 e1 = timer_get_milliseconds();
2305 // time a bunch of cfopens
2307 s2 = timer_get_milliseconds();
2309 for(int idx=0; idx<10000; idx++){
2310 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2315 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2317 e2 = timer_get_milliseconds();
2320 if (Is_standalone) {
2321 std_init_standalone();
2323 os_init( Osreg_class_name, Osreg_app_name );
2324 os_set_title(Osreg_title);
2327 // initialize localization module. Make sure this is down AFTER initialzing OS.
2328 // int t1 = timer_get_milliseconds();
2329 lcl_init( detect_lang() );
2331 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2333 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2336 // verify that he has a valid weapons.tbl
2337 verify_weapons_tbl();
2339 // Output version numbers to registry for auto patching purposes
2340 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2341 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2342 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2344 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2345 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2346 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2348 // show the FPS counter if the config file says so
2349 Show_framerate = os_config_read_uint( "Video", "ShowFPS", Show_framerate );
2351 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2352 Asteroids_enabled = 1;
2355 /////////////////////////////
2357 /////////////////////////////
2359 if (!Is_standalone) {
2363 /////////////////////////////
2365 /////////////////////////////
2367 if ( !Is_standalone ) {
2375 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2378 display_title_screen();
2382 // attempt to load up master tracker registry info (login and password)
2383 Multi_tracker_id = -1;
2385 // pxo login and password
2386 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2388 nprintf(("Network","Error reading in PXO login data\n"));
2389 SDL_strlcpy(Multi_tracker_login, "", sizeof(Multi_tracker_login));
2391 SDL_strlcpy(Multi_tracker_login, ptr, sizeof(Multi_tracker_login));
2393 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2395 nprintf(("Network","Error reading PXO password\n"));
2396 SDL_strlcpy(Multi_tracker_passwd, "", sizeof(Multi_tracker_passwd));
2398 SDL_strlcpy(Multi_tracker_passwd, ptr, sizeof(Multi_tracker_passwd));
2401 // pxo squad name and password
2402 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2404 nprintf(("Network","Error reading in PXO squad name\n"));
2405 SDL_strlcpy(Multi_tracker_squad_name, "", sizeof(Multi_tracker_squad_name));
2407 SDL_strlcpy(Multi_tracker_squad_name, ptr, sizeof(Multi_tracker_squad_name));
2410 // If less than 48MB of RAM, use low memory model.
2411 if ( (Freespace_total_ram < 48) || Use_low_mem ) {
2412 mprintf(( "Using normal memory settings...\n" ));
2413 bm_set_low_mem(1); // Use every other frame of bitmaps
2415 mprintf(( "Using high memory settings...\n" ));
2416 bm_set_low_mem(0); // Use all frames of bitmaps
2419 // load non-darkening pixel defs
2420 palman_load_pixels();
2422 // hud shield icon stuff
2423 hud_shield_game_init();
2425 control_config_common_init(); // sets up localization stuff in the control config
2431 gamesnd_parse_soundstbl();
2436 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2441 player_controls_init();
2444 //if(!Is_standalone){
2452 ship_init(); // read in ships.tbl
2454 mission_campaign_init(); // load in the default campaign
2456 // navmap_init(); // init the navigation map system
2457 context_help_init();
2458 techroom_intel_init(); // parse species.tbl, load intel info
2460 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2461 init_animating_pointer();
2463 mission_brief_common_init(); // Mark all the briefing structures as empty.
2464 gr_font_init(); // loads up all fonts
2466 neb2_init(); // fullneb stuff
2470 player_tips_init(); // helpful tips
2473 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2474 pilot_load_pic_list();
2475 pilot_load_squad_pic_list();
2477 load_animating_pointer(NOX("cursor"), 0, 0);
2479 // initialize alpha colors
2480 alpha_colors_init();
2483 // Game_music_paused = 0;
2487 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2488 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2490 mprintf(("cfile_init() took %d\n", e1 - s1));
2491 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2494 char transfer_text[128];
2496 float Start_time = 0.0f;
2498 float Framerate = 0.0f;
2500 float Timing_total = 0.0f;
2501 float Timing_render2 = 0.0f;
2502 float Timing_render3 = 0.0f;
2503 float Timing_flip = 0.0f;
2504 float Timing_clear = 0.0f;
2506 MONITOR(NumPolysDrawn);
2512 void game_get_framerate()
2514 char text[128] = "";
2516 if ( frame_int == -1 ) {
2518 for (i=0; i<FRAME_FILTER; i++ ) {
2519 frametimes[i] = 0.0f;
2524 frametotal -= frametimes[frame_int];
2525 frametotal += flFrametime;
2526 frametimes[frame_int] = flFrametime;
2527 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2529 if ( frametotal != 0.0 ) {
2530 if ( Framecount >= FRAME_FILTER )
2531 Framerate = FRAME_FILTER / frametotal;
2533 Framerate = Framecount / frametotal;
2534 SDL_snprintf( text, sizeof(text), NOX("FPS: %.1f"), Framerate );
2536 SDL_snprintf( text, sizeof(text), NOX("FPS: ?") );
2540 if (Show_framerate) {
2541 gr_set_color_fast(&HUD_color_debug);
2542 gr_string( 570, 2, text );
2546 void game_show_framerate()
2550 cur_time = f2fl(timer_get_approx_seconds());
2551 if (cur_time - Start_time > 30.0f) {
2552 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2553 Start_time += 1000.0f;
2556 //mprintf(( "%s\n", text ));
2559 if ( Debug_dump_frames )
2563 // possibly show control checking info
2564 control_check_indicate();
2566 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2567 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2568 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2569 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2572 if ( Show_cpu == 1 ) {
2577 dy = gr_get_font_height() + 1;
2579 gr_set_color_fast(&HUD_color_debug);
2582 extern int Gr_textures_in;
2583 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2586 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2588 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2590 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2592 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2594 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2599 extern int Num_pairs; // Number of object pairs that were checked.
2600 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2603 extern int Num_pairs_checked; // What percent of object pairs were checked.
2604 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2606 Num_pairs_checked = 0;
2610 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2613 if ( Timing_total > 0.01f ) {
2614 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2616 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2618 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2620 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2622 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2631 dy = gr_get_font_height() + 1;
2633 gr_set_color_fast(&HUD_color_debug);
2636 extern int TotalRam;
2637 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2642 extern int Model_ram;
2643 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2647 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2649 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2653 extern int Gr_textures_in;
2654 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2659 if ( Show_player_pos ) {
2663 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));
2666 MONITOR_INC(NumPolys, modelstats_num_polys);
2667 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2668 MONITOR_INC(NumVerts, modelstats_num_verts );
2670 modelstats_num_polys = 0;
2671 modelstats_num_polys_drawn = 0;
2672 modelstats_num_verts = 0;
2673 modelstats_num_sortnorms = 0;
2677 void game_show_standalone_framerate()
2679 float frame_rate=30.0f;
2680 if ( frame_int == -1 ) {
2682 for (i=0; i<FRAME_FILTER; i++ ) {
2683 frametimes[i] = 0.0f;
2688 frametotal -= frametimes[frame_int];
2689 frametotal += flFrametime;
2690 frametimes[frame_int] = flFrametime;
2691 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2693 if ( frametotal != 0.0 ) {
2694 if ( Framecount >= FRAME_FILTER ){
2695 frame_rate = FRAME_FILTER / frametotal;
2697 frame_rate = Framecount / frametotal;
2700 std_set_standalone_fps(frame_rate);
2704 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2705 void game_show_time_left()
2709 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2710 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2711 // checking how much time is left
2713 if ( Mission_end_time == -1 ){
2717 diff = f2i(Mission_end_time - Missiontime);
2718 // be sure to bash to 0. diff could be negative on frame that we quit mission
2723 hud_set_default_color();
2724 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2727 //========================================================================================
2728 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2729 //========================================================================================
2733 DCF(ai_pause,"Pauses ai")
2736 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2737 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2738 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2739 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2742 obj_init_all_ships_physics();
2745 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2746 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2749 DCF(single_step,"Single steps the game")
2752 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2753 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2754 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2755 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2757 last_single_step = 0; // Make so single step waits a frame before stepping
2760 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2761 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2764 DCF_BOOL(physics_pause, physics_paused)
2765 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2766 DCF_BOOL(ai_firing, Ai_firing_enabled )
2768 // Create some simple aliases to these commands...
2769 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2770 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2771 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2772 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2773 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2776 //========================================================================================
2777 //========================================================================================
2780 void game_training_pause_do()
2784 key = game_check_key();
2786 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2793 void game_increase_skill_level()
2796 if (Game_skill_level >= NUM_SKILL_LEVELS){
2797 Game_skill_level = 0;
2801 int Player_died_time;
2803 int View_percent = 100;
2806 DCF(view, "Sets the percent of the 3d view to render.")
2809 dc_get_arg(ARG_INT);
2810 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2811 View_percent = Dc_arg_int;
2813 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2819 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2823 dc_printf("View is set to %d%%\n", View_percent );
2828 // Set the clip region for the 3d rendering window
2829 void game_set_view_clip()
2831 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2832 // Set the clip region for the letterbox "dead view"
2833 int yborder = gr_screen.max_h/4;
2835 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2836 // J.S. I've changed my ways!! See the new "no constants" code!!!
2837 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2839 // Set the clip region for normal view
2840 if ( View_percent >= 100 ) {
2843 int xborder, yborder;
2845 if ( View_percent < 5 ) {
2849 float fp = i2fl(View_percent)/100.0f;
2850 int fi = fl2i(fl_sqrt(fp)*100.0f);
2851 if ( fi > 100 ) fi=100;
2853 xborder = ( gr_screen.max_w*(100-fi) )/200;
2854 yborder = ( gr_screen.max_h*(100-fi) )/200;
2856 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2862 void show_debug_stuff()
2865 int laser_count = 0, missile_count = 0;
2867 for (i=0; i<MAX_OBJECTS; i++) {
2868 if (Objects[i].type == OBJ_WEAPON){
2869 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2871 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2877 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2880 extern int Tool_enabled;
2882 time_t tst_time = 0;
2885 int tst_bitmap = -1;
2887 float tst_offset, tst_offset_total;
2890 void game_tst_frame_pre()
2898 g3_rotate_vertex(&v, &tst_pos);
2899 g3_project_vertex(&v);
2902 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2906 // big ship? always tst
2908 // within 3000 meters
2909 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2913 // within 300 meters
2914 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2921 void game_tst_frame()
2931 tst_time = time(NULL);
2933 // load the tst bitmap
2934 switch((int)frand_range(0.0f, 3.0)){
2936 tst_bitmap = bm_load("ig_jim");
2938 mprintf(("TST 0\n"));
2942 tst_bitmap = bm_load("ig_kan");
2944 mprintf(("TST 1\n"));
2948 tst_bitmap = bm_load("ig_jim");
2950 mprintf(("TST 2\n"));
2954 tst_bitmap = bm_load("ig_kan");
2956 mprintf(("TST 3\n"));
2965 // get the tst bitmap dimensions
2967 bm_get_info(tst_bitmap, &w, &h);
2970 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2972 snd_play(&Snds[SND_VASUDAN_BUP]);
2974 // tst x and direction
2978 tst_offset_total = (float)w;
2979 tst_offset = (float)w;
2981 tst_x = (float)gr_screen.max_w;
2982 tst_offset_total = (float)-w;
2983 tst_offset = (float)w;
2991 float diff = (tst_offset_total / 0.5f) * flFrametime;
2997 tst_offset -= fl_abs(diff);
2998 } else if(tst_mode == 2){
3001 tst_offset -= fl_abs(diff);
3005 gr_set_bitmap(tst_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3006 gr_bitmap((int)tst_x, (int)tst_y);
3009 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3013 // if we passed the switch point
3014 if(tst_offset <= 0.0f){
3019 tst_stamp = timestamp(1000);
3020 tst_offset = fl_abs(tst_offset_total);
3031 void game_tst_mark(object *objp, ship *shipp)
3040 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3043 sip = &Ship_info[shipp->ship_info_index];
3050 tst_pos = objp->pos;
3051 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3057 extern void render_shields();
3059 void player_repair_frame(float frametime)
3061 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3063 for(idx=0;idx<MAX_PLAYERS;idx++){
3066 np = &Net_players[idx];
3068 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)){
3070 // don't rearm/repair if the player is dead or dying/departing
3071 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3072 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3077 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3078 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3084 #define NUM_FRAMES_TEST 300
3085 #define NUM_MIXED_SOUNDS 16
3086 void do_timing_test(float flFrametime)
3088 static int framecount = 0;
3089 static int test_running = 0;
3090 static float test_time = 0.0f;
3092 static int snds[NUM_MIXED_SOUNDS];
3095 if ( test_running ) {
3097 test_time += flFrametime;
3098 if ( framecount >= NUM_FRAMES_TEST ) {
3100 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3101 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3106 if ( Test_begin == 1 ) {
3112 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3115 // start looping digital sounds
3116 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3117 snds[i] = snd_play_looping( &Snds[i], 0.0f);
3124 DCF(dcf_fov, "Change the field of view")
3127 dc_get_arg(ARG_FLOAT|ARG_NONE);
3128 if ( Dc_arg_type & ARG_NONE ) {
3129 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3130 dc_printf( "Zoom factor reset\n" );
3132 if ( Dc_arg_type & ARG_FLOAT ) {
3133 if (Dc_arg_float < 0.25f) {
3134 Viewer_zoom = 0.25f;
3135 dc_printf("Zoom factor pinned at 0.25.\n");
3136 } else if (Dc_arg_float > 1.25f) {
3137 Viewer_zoom = 1.25f;
3138 dc_printf("Zoom factor pinned at 1.25.\n");
3140 Viewer_zoom = Dc_arg_float;
3146 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3149 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3153 DCF(framerate_cap, "Sets the framerate cap")
3156 dc_get_arg(ARG_INT);
3157 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3158 Framerate_cap = Dc_arg_int;
3160 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3166 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3167 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3168 dc_printf("[n] must be from 1 to 120.\n");
3172 if ( Framerate_cap )
3173 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3175 dc_printf("There is no framerate cap currently active.\n");
3179 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3180 int Show_viewing_from_self = 0;
3182 void say_view_target()
3184 object *view_target;
3186 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3187 view_target = &Objects[Player_ai->target_objnum];
3189 view_target = Player_obj;
3191 if (Game_mode & GM_DEAD) {
3192 if (Player_ai->target_objnum != -1)
3193 view_target = &Objects[Player_ai->target_objnum];
3196 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3197 if (view_target != Player_obj){
3199 char *view_target_name = NULL;
3200 switch(Objects[Player_ai->target_objnum].type) {
3202 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3205 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3206 Viewer_mode &= ~VM_OTHER_SHIP;
3208 case OBJ_JUMP_NODE: {
3209 char jump_node_name[128];
3210 SDL_strlcpy(jump_node_name, XSTR( "jump node", 184), sizeof(jump_node_name));
3211 view_target_name = jump_node_name;
3212 Viewer_mode &= ~VM_OTHER_SHIP;
3221 if ( view_target_name ) {
3222 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3223 Show_viewing_from_self = 1;
3226 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3227 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3228 Show_viewing_from_self = 1;
3230 if (Show_viewing_from_self)
3231 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3236 Last_view_target = view_target;
3240 float Game_hit_x = 0.0f;
3241 float Game_hit_y = 0.0f;
3243 // Reset at the beginning of each frame
3244 void game_whack_reset()
3250 // Apply a 2d whack to the player
3251 void game_whack_apply( float x, float y )
3253 // Do some force feedback
3254 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3260 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3263 // call to apply a "shudder"
3264 void game_shudder_apply(int time, float intensity)
3266 Game_shudder_time = timestamp(time);
3267 Game_shudder_total = time;
3268 Game_shudder_intensity = intensity;
3271 #define FF_SCALE 10000
3272 void apply_hud_shake(matrix *eye_orient)
3274 if (Viewer_obj == Player_obj) {
3275 physics_info *pi = &Player_obj->phys_info;
3283 // Make eye shake due to afterburner
3284 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3287 dtime = timestamp_until(pi->afterburner_decay);
3291 tangles.p += 0.07f * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3292 tangles.h += 0.07f * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3295 // Make eye shake due to engine wash
3297 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3300 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX;
3301 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX;
3303 // get the intensity
3304 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3308 vm_vec_rand_vec_quick(&rand_vec);
3311 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3315 // make hud shake due to shuddering
3316 if(Game_shudder_time != -1){
3317 // if the timestamp has elapsed
3318 if(timestamp_elapsed(Game_shudder_time)){
3319 Game_shudder_time = -1;
3321 // otherwise apply some shudder
3325 dtime = timestamp_until(Game_shudder_time);
3329 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));
3330 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));
3335 vm_angles_2_matrix(&tm, &tangles);
3336 SDL_assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3337 SDL_assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3338 SDL_assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3339 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3344 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3346 // Player's velocity just before he blew up. Used to keep camera target moving.
3347 vector Dead_player_last_vel = { { { 1.0f, 1.0f, 1.0f } } };
3349 // Set eye_pos and eye_orient based on view mode.
3350 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3354 static int last_Viewer_mode = 0;
3355 static int last_Game_mode = 0;
3356 static int last_Viewer_objnum = -1;
3358 // This code is supposed to detect camera "cuts"... like going between
3361 // determine if we need to regenerate the nebula
3362 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3363 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3364 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3365 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3366 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3367 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3368 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3369 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3370 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3373 // regenerate the nebula
3377 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3378 //mprintf(( "************** Camera cut! ************\n" ));
3379 last_Viewer_mode = Viewer_mode;
3380 last_Game_mode = Game_mode;
3382 // Camera moved. Tell stars & debris to not do blurring.
3388 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3389 player_display_packlock_view();
3392 game_set_view_clip();
3394 if (Game_mode & GM_DEAD) {
3395 vector vec_to_deader, view_pos;
3398 Viewer_mode |= VM_DEAD_VIEW;
3400 if (Player_ai->target_objnum != -1) {
3401 int view_from_player = 1;
3403 if (Viewer_mode & VM_OTHER_SHIP) {
3404 // View from target.
3405 Viewer_obj = &Objects[Player_ai->target_objnum];
3407 last_Viewer_objnum = Player_ai->target_objnum;
3409 if ( Viewer_obj->type == OBJ_SHIP ) {
3410 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3411 view_from_player = 0;
3414 last_Viewer_objnum = -1;
3417 if ( view_from_player ) {
3418 // View target from player ship.
3420 *eye_pos = Player_obj->pos;
3421 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3422 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3425 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3427 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3428 dist += flFrametime * 16.0f;
3430 vm_vec_scale(&vec_to_deader, -dist);
3431 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3433 view_pos = Player_obj->pos;
3435 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3436 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3437 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3438 Dead_player_last_vel = Player_obj->phys_info.vel;
3439 //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));
3440 } else if (Player_ai->target_objnum != -1) {
3441 view_pos = Objects[Player_ai->target_objnum].pos;
3443 // Make camera follow explosion, but gradually slow down.
3444 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3445 view_pos = Player_obj->pos;
3446 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3447 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3450 *eye_pos = Dead_camera_pos;
3452 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3454 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3459 // if supernova shockwave
3460 if(supernova_camera_cut()){
3464 // call it dead view
3465 Viewer_mode |= VM_DEAD_VIEW;
3467 // set eye pos and orient
3468 supernova_set_view(eye_pos, eye_orient);
3470 // If already blown up, these other modes can override.
3471 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3472 Viewer_mode &= ~VM_DEAD_VIEW;
3474 Viewer_obj = Player_obj;
3476 if (Viewer_mode & VM_OTHER_SHIP) {
3477 if (Player_ai->target_objnum != -1){
3478 Viewer_obj = &Objects[Player_ai->target_objnum];
3479 last_Viewer_objnum = Player_ai->target_objnum;
3481 Viewer_mode &= ~VM_OTHER_SHIP;
3482 last_Viewer_objnum = -1;
3485 last_Viewer_objnum = -1;
3488 if (Viewer_mode & VM_EXTERNAL) {
3491 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3492 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3494 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3496 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3497 vm_vec_normalize(&eye_dir);
3498 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3501 // Modify the orientation based on head orientation.
3502 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3504 } else if ( Viewer_mode & VM_CHASE ) {
3507 if ( Viewer_obj->phys_info.speed < 0.1 )
3508 move_dir = Viewer_obj->orient.v.fvec;
3510 move_dir = Viewer_obj->phys_info.vel;
3511 vm_vec_normalize(&move_dir);
3514 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3515 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3516 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3517 vm_vec_normalize(&eye_dir);
3519 // JAS: I added the following code because if you slew up using
3520 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3521 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3522 // call because the up and the forward vector are the same. I fixed
3523 // it by adding in a fraction of the right vector all the time to the
3525 vector tmp_up = Viewer_obj->orient.v.uvec;
3526 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3528 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3531 // Modify the orientation based on head orientation.
3532 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3533 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3534 *eye_pos = Camera_pos;
3536 ship * shipp = &Ships[Player_obj->instance];
3538 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3539 vm_vec_normalize(&eye_dir);
3540 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3543 // get an eye position based upon the correct type of object
3544 switch(Viewer_obj->type){
3546 // make a call to get the eye point for the player object
3547 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3550 // make a call to get the eye point for the player object
3551 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3557 #ifdef JOHNS_DEBUG_CODE
3558 john_debug_stuff(&eye_pos, &eye_orient);
3564 apply_hud_shake(eye_orient);
3566 // setup neb2 rendering
3567 neb2_render_setup(eye_pos, eye_orient);
3571 extern void ai_debug_render_stuff();
3574 int Game_subspace_effect = 0;
3575 DCF_BOOL( subspace, Game_subspace_effect );
3577 // Does everything needed to render a frame
3578 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3582 g3_start_frame(game_zbuffer);
3583 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3585 // maybe offset the HUD (jitter stuff)
3586 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3587 HUD_set_offsets(Viewer_obj, !dont_offset);
3589 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3590 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3591 // must be done before ships are rendered
3592 if ( MULTIPLAYER_CLIENT ) {
3593 shield_point_multi_setup();
3596 if ( Game_subspace_effect ) {
3597 stars_draw(0,0,0,1);
3599 stars_draw(1,1,1,0);
3602 obj_render_all(obj_render);
3603 beam_render_all(); // render all beam weapons
3604 particle_render_all(); // render particles after everything else.
3605 trail_render_all(); // render missilie trails after everything else.
3606 mflash_render_all(); // render all muzzle flashes
3608 // Why do we not show the shield effect in these modes? Seems ok.
3609 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3613 // render nebula lightning
3616 // render local player nebula
3617 neb2_render_player();
3620 ai_debug_render_stuff();
3623 #ifndef RELEASE_REAL
3624 // game_framerate_check();
3628 extern void snd_spew_debug_info();
3629 snd_spew_debug_info();
3632 //================ END OF 3D RENDERING STUFF ====================
3636 if( (Game_detail_flags & DETAIL_FLAG_HUD) && (!(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )) ) {
3637 hud_maybe_clear_head_area();
3638 anim_render_all(0, flFrametime);
3641 extern int Multi_display_netinfo;
3642 if(Multi_display_netinfo){
3643 extern void multi_display_netinfo();
3644 multi_display_netinfo();
3647 game_tst_frame_pre();
3650 do_timing_test(flFrametime);
3654 extern int OO_update_index;
3655 multi_rate_display(OO_update_index, 375, 0);
3660 extern void oo_display();
3667 //#define JOHNS_DEBUG_CODE 1
3669 #ifdef JOHNS_DEBUG_CODE
3670 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3672 //if ( key_pressed(SDLK_LSHIFT) )
3674 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3676 model_subsystem *turret = tsys->system_info;
3678 if (turret->type == SUBSYSTEM_TURRET ) {
3679 vector v.fvec, v.uvec;
3680 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3682 ship_model_start(tobj);
3684 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3685 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3686 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3688 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3690 ship_model_stop(tobj);
3700 // following function for dumping frames for purposes of building trailers.
3703 // function to toggle state of dumping every frame into PCX when playing the game
3704 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3708 if ( Debug_dump_frames == 0 ) {
3710 Debug_dump_frames = 15;
3711 Debug_dump_trigger = 0;
3712 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3713 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3716 Debug_dump_frames = 0;
3717 Debug_dump_trigger = 0;
3718 gr_dump_frame_stop();
3719 dc_printf( "Frame dumping is now OFF\n" );
3725 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3729 if ( Debug_dump_frames == 0 ) {
3731 Debug_dump_frames = 15;
3732 Debug_dump_trigger = 1;
3733 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3734 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3737 Debug_dump_frames = 0;
3738 Debug_dump_trigger = 0;
3739 gr_dump_frame_stop();
3740 dc_printf( "Frame dumping is now OFF\n" );
3746 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3750 if ( Debug_dump_frames == 0 ) {
3752 Debug_dump_frames = 30;
3753 Debug_dump_trigger = 0;
3754 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3755 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3758 Debug_dump_frames = 0;
3759 Debug_dump_trigger = 0;
3760 gr_dump_frame_stop();
3761 dc_printf( "Frame dumping is now OFF\n" );
3767 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3771 if ( Debug_dump_frames == 0 ) {
3773 Debug_dump_frames = 30;
3774 Debug_dump_trigger = 1;
3775 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3776 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3779 Debug_dump_frames = 0;
3780 Debug_dump_trigger = 0;
3781 gr_dump_frame_stop();
3782 dc_printf( "Triggered frame dumping is now OFF\n" );
3788 void game_maybe_dump_frame()
3790 if ( !Debug_dump_frames ){
3794 if( Debug_dump_trigger && !key_pressed(SDLK_q) ){
3801 Debug_dump_frame_num++;
3807 extern int Player_dead_state;
3809 // Flip the page and time how long it took.
3810 void game_flip_page_and_time_it()
3815 t1 = timer_get_fixed_seconds();
3817 t2 = timer_get_fixed_seconds();
3820 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3821 SDL_snprintf( transfer_text, sizeof(transfer_text), NOX("%d MB/s"), fixmuldiv(t,65,d) );
3828 void game_simulation_frame()
3830 // blow ships up in multiplayer dogfight
3831 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){
3832 // blow up all non-player ships
3833 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3836 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3838 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)){
3839 moveup = GET_NEXT(moveup);
3842 shipp = &Ships[Objects[moveup->objnum].instance];
3843 sip = &Ship_info[shipp->ship_info_index];
3845 // only blow up small ships
3846 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3847 // function to simply explode a ship where it is currently at
3848 ship_self_destruct( &Objects[moveup->objnum] );
3851 moveup = GET_NEXT(moveup);
3857 // process AWACS stuff - do this first thing
3860 // single player, set Player hits_this_frame to 0
3861 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3862 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3863 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3867 supernova_process();
3868 if(supernova_active() >= 5){
3872 // fire targeting lasers now so that
3873 // 1 - created this frame
3874 // 2 - collide this frame
3875 // 3 - render this frame
3876 // 4 - ignored and deleted next frame
3877 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3879 ship_process_targeting_lasers();
3881 // do this here so that it works for multiplayer
3883 // get viewer direction
3884 int viewer_direction = PHYSICS_VIEWER_REAR;
3886 if(Viewer_mode == 0){
3887 viewer_direction = PHYSICS_VIEWER_FRONT;
3889 if(Viewer_mode & VM_PADLOCK_UP){
3890 viewer_direction = PHYSICS_VIEWER_UP;
3892 else if(Viewer_mode & VM_PADLOCK_REAR){
3893 viewer_direction = PHYSICS_VIEWER_REAR;
3895 else if(Viewer_mode & VM_PADLOCK_LEFT){
3896 viewer_direction = PHYSICS_VIEWER_LEFT;
3898 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3899 viewer_direction = PHYSICS_VIEWER_RIGHT;
3902 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3904 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3907 #define VM_PADLOCK_UP (1 << 7)
3908 #define VM_PADLOCK_REAR (1 << 8)
3909 #define VM_PADLOCK_LEFT (1 << 9)
3910 #define VM_PADLOCK_RIGHT (1 << 10)
3912 // evaluate mission departures and arrivals before we process all objects.
3913 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3915 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3916 // ships/wing packets.
3917 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3918 mission_parse_eval_stuff();
3921 // if we're an observer, move ourselves seperately from the standard physics
3922 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3923 obj_observer_move(flFrametime);
3926 // move all the objects now
3927 obj_move_all(flFrametime);
3929 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3930 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3931 // ship_check_cargo_all();
3932 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3933 mission_eval_goals();
3937 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3938 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3939 training_check_objectives();
3942 // do all interpolation now
3943 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3944 // client side processing of warping in effect stages
3945 multi_do_client_warp(flFrametime);
3947 // client side movement of an observer
3948 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3949 obj_observer_move(flFrametime);
3952 // move all objects - does interpolation now as well
3953 obj_move_all(flFrametime);
3956 // only process the message queue when the player is "in" the game
3957 if ( !Pre_player_entry ){
3958 message_queue_process(); // process any messages send to the player
3961 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3962 message_maybe_distort(); // maybe distort incoming message if comms damaged
3963 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3964 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3965 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3968 if(!(Game_mode & GM_STANDALONE_SERVER)){
3969 // process some stuff every frame (before frame is rendered)
3970 emp_process_local();
3972 hud_update_frame(); // update hud systems
3974 if (!physics_paused) {
3975 // Move particle system
3976 particle_move_all(flFrametime);
3978 // Move missile trails
3979 trail_move_all(flFrametime);
3981 // process muzzle flashes
3982 mflash_process_all();
3984 // Flash the gun flashes
3985 shipfx_flash_do_frame(flFrametime);
3987 shockwave_move_all(flFrametime); // update all the shockwaves
3990 // subspace missile strikes
3993 obj_snd_do_frame(); // update the object-linked persistant sounds
3994 game_maybe_update_sound_environment();
3995 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3997 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3999 if ( Game_subspace_effect ) {
4000 game_start_subspace_ambient_sound();
4006 // Maybe render and process the dead-popup
4007 void game_maybe_do_dead_popup(float frametime)
4009 if ( popupdead_is_active() ) {
4011 int choice = popupdead_do_frame(frametime);
4013 if ( Game_mode & GM_NORMAL ) {
4016 gameseq_post_event(GS_EVENT_ENTER_GAME);
4020 gameseq_post_event(GS_EVENT_END_GAME);
4024 gameseq_post_event(GS_EVENT_START_GAME);
4027 // this should only happen during a red alert mission
4030 SDL_assert(The_mission.red_alert);
4031 if(!The_mission.red_alert){
4032 gameseq_post_event(GS_EVENT_START_GAME);
4036 // choose the previous mission
4037 mission_campaign_previous_mission();
4039 gameseq_post_event(GS_EVENT_START_GAME);
4049 case POPUPDEAD_DO_MAIN_HALL:
4050 multi_quit_game(PROMPT_NONE,-1);
4053 case POPUPDEAD_DO_RESPAWN:
4054 multi_respawn_normal();
4055 event_music_player_respawn();
4058 case POPUPDEAD_DO_OBSERVER:
4059 multi_respawn_observer();
4060 event_music_player_respawn_as_observer();
4069 if ( leave_popup ) {
4075 // returns true if player is actually in a game_play stats
4076 int game_actually_playing()
4080 state = gameseq_get_state();
4081 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4087 // Draw the 2D HUD gauges
4088 void game_render_hud_2d()
4090 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4094 HUD_render_2d(flFrametime);
4098 // Draw the 3D-dependant HUD gauges
4099 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4101 g3_start_frame(0); // 0 = turn zbuffering off
4102 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4104 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4105 HUD_render_3d(flFrametime);
4109 game_sunspot_process(flFrametime);
4111 // Diminish the palette effect
4112 game_flash_diminish(flFrametime);
4120 int actually_playing;
4121 fix total_time1, total_time2;
4122 fix render2_time1=0, render2_time2=0;
4123 fix render3_time1=0, render3_time2=0;
4124 fix flip_time1=0, flip_time2=0;
4125 fix clear_time1=0, clear_time2=0;
4131 if (Framerate_delay) {
4132 int start_time = timer_get_milliseconds();
4133 while (timer_get_milliseconds() < start_time + Framerate_delay)
4139 demo_do_frame_start();
4141 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4146 // start timing frame
4147 timing_frame_start();
4149 total_time1 = timer_get_fixed_seconds();
4151 // var to hold which state we are in
4152 actually_playing = game_actually_playing();
4154 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4155 if (!(Game_mode & GM_STANDALONE_SERVER)){
4156 SDL_assert( OBJ_INDEX(Player_obj) >= 0 );
4160 if (Missiontime > Entry_delay_time){
4161 Pre_player_entry = 0;
4163 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4166 // Note: These are done even before the player enters, else buffers can overflow.
4167 if (! (Game_mode & GM_STANDALONE_SERVER)){
4171 shield_frame_init();
4173 if ( Player->control_mode != PCM_NORMAL )
4176 if ( !Pre_player_entry && actually_playing ) {
4177 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4179 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4180 game_process_keys();
4182 // don't read flying controls if we're playing a demo back
4183 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4184 read_player_controls( Player_obj, flFrametime);
4188 // if we're not the master, we may have to send the server-critical ship status button_info bits
4189 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4190 multi_maybe_send_ship_status();
4195 // Reset the whack stuff
4198 // These two lines must be outside of Pre_player_entry code,
4199 // otherwise too many lights are added.
4202 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4206 game_simulation_frame();
4208 // if not actually in a game play state, then return. This condition could only be true in
4209 // a multiplayer game.
4210 if ( !actually_playing ) {
4211 SDL_assert( Game_mode & GM_MULTIPLAYER );
4215 if (!Pre_player_entry) {
4216 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4217 clear_time1 = timer_get_fixed_seconds();
4218 // clear the screen to black
4220 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4224 clear_time2 = timer_get_fixed_seconds();
4225 render3_time1 = timer_get_fixed_seconds();
4226 game_render_frame_setup(&eye_pos, &eye_orient);
4227 game_render_frame( &eye_pos, &eye_orient );
4229 // save the eye position and orientation
4230 if ( Game_mode & GM_MULTIPLAYER ) {
4231 Net_player->s_info.eye_pos = eye_pos;
4232 Net_player->s_info.eye_orient = eye_orient;
4235 hud_show_target_model();
4237 // check to see if we should display the death died popup
4238 if(Game_mode & GM_DEAD_BLEW_UP){
4239 if(Game_mode & GM_MULTIPLAYER){
4240 // catch the situation where we're supposed to be warping out on this transition
4241 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4242 gameseq_post_event(GS_EVENT_DEBRIEF);
4243 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4244 Player_died_popup_wait = -1;
4248 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4249 Player_died_popup_wait = -1;
4255 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4256 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4257 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4258 if(!popupdead_is_active()){
4262 Player_multi_died_check = -1;
4266 render3_time2 = timer_get_fixed_seconds();
4267 render2_time1 = timer_get_fixed_seconds();
4270 game_get_framerate();
4271 game_show_framerate();
4273 game_show_time_left();
4275 // Draw the 2D HUD gauges
4276 if(supernova_active() < 3){
4277 game_render_hud_2d();
4280 game_set_view_clip();
4282 // Draw 3D HUD gauges
4283 game_render_hud_3d(&eye_pos, &eye_orient);
4287 render2_time2 = timer_get_fixed_seconds();
4289 // maybe render and process the dead popup
4290 game_maybe_do_dead_popup(flFrametime);
4292 // start timing frame
4293 timing_frame_stop();
4294 // timing_display(30, 10);
4296 // If a regular popup is active, don't flip (popup code flips)
4297 if( !popup_running_state() ){
4298 flip_time1 = timer_get_fixed_seconds();
4299 game_flip_page_and_time_it();
4300 flip_time2 = timer_get_fixed_seconds();
4304 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4307 game_show_standalone_framerate();
4311 game_do_training_checks();
4314 // process lightning (nebula only)
4317 total_time2 = timer_get_fixed_seconds();
4319 // Got some timing numbers
4320 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4321 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4322 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4323 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4324 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4327 demo_do_frame_end();
4329 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4335 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4336 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4337 // died. This resulted in screwed up death sequences.
4339 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4340 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4341 static int timer_paused=0;
4342 #if defined(TIMER_TEST) && !defined(NDEBUG)
4343 static int stop_count,start_count;
4344 static int time_stopped,time_started;
4346 int saved_timestamp_ticker = -1;
4348 void game_reset_time()
4350 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4354 // Last_time = timer_get_fixed_seconds();
4360 void game_stop_time()
4362 if (timer_paused==0) {
4364 time = timer_get_fixed_seconds();
4365 // Save how much time progressed so far in the frame so we can
4366 // use it when we unpause.
4367 Last_delta_time = time - Last_time;
4369 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4370 if (Last_delta_time < 0) {
4371 #if defined(TIMER_TEST) && !defined(NDEBUG)
4372 Int3(); //get Matt!!!!
4374 Last_delta_time = 0;
4376 #if defined(TIMER_TEST) && !defined(NDEBUG)
4377 time_stopped = time;
4380 // Stop the timer_tick stuff...
4381 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4382 saved_timestamp_ticker = timestamp_ticker;
4386 #if defined(TIMER_TEST) && !defined(NDEBUG)
4391 void game_start_time()
4394 SDL_assert(timer_paused >= 0);
4395 if (timer_paused==0) {
4397 time = timer_get_fixed_seconds();
4398 #if defined(TIMER_TEST) && !defined(NDEBUG)
4400 Int3(); //get Matt!!!!
4403 // Take current time, and set it backwards to account for time
4404 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4405 // will be correct when it goes to calculate the frametime next
4407 Last_time = time - Last_delta_time;
4408 #if defined(TIMER_TEST) && !defined(NDEBUG)
4409 time_started = time;
4412 // Restore the timer_tick stuff...
4413 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4414 SDL_assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4415 timestamp_ticker = saved_timestamp_ticker;
4416 saved_timestamp_ticker = -1;
4419 #if defined(TIMER_TEST) && !defined(NDEBUG)
4425 void game_set_frametime(int state)
4428 float frame_cap_diff;
4430 thistime = timer_get_fixed_seconds();
4432 if ( Last_time == 0 )
4433 Frametime = F1_0 / 30;
4435 Frametime = thistime - Last_time;
4437 // Frametime = F1_0 / 30;
4439 fix debug_frametime = Frametime; // Just used to display frametime.
4441 // If player hasn't entered mission yet, make frame take 1/4 second.
4442 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4445 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4447 fix frame_speed = F1_0 / Debug_dump_frames;
4449 if (Frametime > frame_speed ){
4450 nprintf(("warning","slow frame: %x\n",Frametime));
4453 thistime = timer_get_fixed_seconds();
4454 Frametime = thistime - Last_time;
4455 } while (Frametime < frame_speed );
4457 Frametime = frame_speed;
4461 SDL_assert( Framerate_cap > 0 );
4463 // Cap the framerate so it doesn't get too high.
4467 cap = F1_0/Framerate_cap;
4468 if (Frametime < cap) {
4469 thistime = cap - Frametime;
4470 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4471 SDL_Delay( fl2i(f2fl(thistime) * 1000.0f) );
4473 thistime = timer_get_fixed_seconds();
4477 if((Game_mode & GM_STANDALONE_SERVER) &&
4478 (f2fl(Frametime) < (1.0f/(float)Multi_options_g.std_framecap))){
4480 frame_cap_diff = (1.0f/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4481 SDL_Delay( fl2i(frame_cap_diff * 1000.0f) );
4483 thistime += fl2f((frame_cap_diff));
4485 Frametime = thistime - Last_time;
4488 // If framerate is too low, cap it.
4489 if (Frametime > MAX_FRAMETIME) {
4491 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4493 // to remove warnings in release build
4494 debug_frametime = fl2f(flFrametime);
4496 Frametime = MAX_FRAMETIME;
4499 Frametime = fixmul(Frametime, Game_time_compression);
4501 Last_time = thistime;
4502 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4504 flFrametime = f2fl(Frametime);
4505 //if(!(Game_mode & GM_PLAYING_DEMO)){
4506 timestamp_inc(flFrametime);
4508 /* if ((Framecount > 0) && (Framecount < 10)) {
4509 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4514 // This is called from game_do_frame(), and from navmap_do_frame()
4515 void game_update_missiontime()
4517 // TODO JAS: Put in if and move this into game_set_frametime,
4518 // fix navmap to call game_stop/start_time
4519 //if ( !timer_paused )
4520 Missiontime += Frametime;
4523 void game_do_frame()
4525 game_set_frametime(GS_STATE_GAME_PLAY);
4526 game_update_missiontime();
4528 if (Game_mode & GM_STANDALONE_SERVER) {
4529 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4532 if ( game_single_step && (last_single_step == game_single_step) ) {
4533 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4534 while( key_checkch() == 0 )
4536 os_set_title( XSTR( "FreeSpace", 171) );
4537 Last_time = timer_get_fixed_seconds();
4540 last_single_step = game_single_step;
4542 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4543 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4547 Keep_mouse_centered = 0;
4548 monitor_update(); // Update monitor variables
4551 void multi_maybe_do_frame()
4553 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4558 int Joymouse_button_status = 0;
4560 // Flush all input devices
4568 Joymouse_button_status = 0;
4570 //mprintf(("Game flush!\n" ));
4573 // function for multiplayer only which calls game_do_state_common() when running the
4575 void game_do_dc_networking()
4577 SDL_assert( Game_mode & GM_MULTIPLAYER );
4579 game_do_state_common( gameseq_get_state() );
4582 // Call this whenever in a loop, or when you need to check for a keystroke.
4583 int game_check_key()
4589 // convert keypad enter to normal enter
4590 if ((k & KEY_MASK) == SDLK_KP_ENTER)
4591 k = (k & ~KEY_MASK) | SDLK_RETURN;
4596 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4598 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4599 static int Demo_show_trailer_timestamp = 0;
4601 void demo_reset_trailer_timer()
4603 Demo_show_trailer_timestamp = timer_get_milliseconds();
4606 void demo_maybe_show_trailer(int k)
4609 // if key pressed, reset demo trailer timer
4611 demo_reset_trailer_timer();
4615 // if mouse moved, reset demo trailer timer
4618 mouse_get_delta(&dx, &dy);
4619 if ( (dx > 0) || (dy > 0) ) {
4620 demo_reset_trailer_timer();
4624 // if joystick has moved, reset demo trailer timer
4627 joy_get_delta(&dx, &dy);
4628 if ( (dx > 0) || (dy > 0) ) {
4629 demo_reset_trailer_timer();
4633 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4634 // the low-level code. Ugly, I know... but was the simplest and most
4637 // if 30 seconds since last demo trailer time reset, launch movie
4638 if ( os_foreground() ) {
4639 int now = timer_get_milliseconds();
4640 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4641 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4643 movie_play( NOX("fstrailer2.mve") );
4644 demo_reset_trailer_timer();
4652 // same as game_check_key(), except this is used while actually in the game. Since there
4653 // generally are differences between game control keys and general UI keys, makes sense to
4654 // have seperate functions for each case. If you are not checking a game control while in a
4655 // mission, you should probably be using game_check_key() instead.
4660 if (!os_foreground()) {
4665 // If we're in a single player game, pause it.
4666 if (!(Game_mode & GM_MULTIPLAYER)){
4667 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4668 game_process_pause_key();
4675 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4676 demo_maybe_show_trailer(k);
4679 // Move the mouse cursor with the joystick.
4680 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4681 // Move the mouse cursor with the joystick
4685 joy_get_pos( &jx, &jy, &jz, &jr );
4687 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4688 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4691 mouse_get_real_pos( &mx, &my );
4692 mouse_set_pos( mx+dx, my+dy );
4697 m = mouse_down(MOUSE_LEFT_BUTTON);
4699 if ( j != Joymouse_button_status ) {
4700 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4701 Joymouse_button_status = j;
4703 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4704 } else if ( (!j) && (m) ) {
4705 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4710 // if we should be ignoring keys because of some multiplayer situations
4711 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4715 // If a popup is running, don't process all the Fn keys
4716 if( popup_active() ) {
4720 state = gameseq_get_state();
4722 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4725 case KEY_DEBUGGED + SDLK_BACKSPACE:
4730 launch_context_help();
4735 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4737 // don't allow f2 while warping out in multiplayer
4738 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4743 case GS_STATE_INITIAL_PLAYER_SELECT:
4744 case GS_STATE_OPTIONS_MENU:
4745 case GS_STATE_HUD_CONFIG:
4746 case GS_STATE_CONTROL_CONFIG:
4747 case GS_STATE_DEATH_DIED:
4748 case GS_STATE_DEATH_BLEW_UP:
4749 case GS_STATE_VIEW_MEDALS:
4753 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4760 // hotkey selection screen -- only valid from briefing and beyond.
4762 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
4763 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) ) {
4764 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4770 case KEY_DEBUGGED + SDLK_F3:
4771 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4774 case KEY_DEBUGGED + SDLK_F4:
4775 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4779 if(Game_mode & GM_MULTIPLAYER){
4780 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4781 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4785 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4786 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4792 case SDLK_ESCAPE | KEY_SHIFTED:
4793 // make sure to quit properly out of multiplayer
4794 if(Game_mode & GM_MULTIPLAYER){
4795 multi_quit_game(PROMPT_NONE);
4798 gameseq_post_event( GS_EVENT_QUIT_GAME );
4803 case KEY_DEBUGGED + SDLK_p:
4806 case SDLK_PRINTSCREEN:
4808 static int counter = 0;
4813 SDL_snprintf( tmp_name, sizeof(tmp_name), NOX("screen%02d"), counter );
4815 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4816 gr_print_screen(tmp_name);
4824 case KEY_SHIFTED | SDLK_RETURN: {
4826 #if !defined(NDEBUG)
4828 if ( Game_mode & GM_NORMAL ){
4832 // if we're in multiplayer mode, do some special networking
4833 if(Game_mode & GM_MULTIPLAYER){
4834 debug_console(game_do_dc_networking);
4841 if ( Game_mode & GM_NORMAL )
4855 gameseq_post_event(GS_EVENT_QUIT_GAME);
4858 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4861 void camera_set_position( vector *pos )
4866 void camera_set_orient( matrix *orient )
4868 Camera_orient = *orient;
4871 void camera_set_velocity( vector *vel, int instantaneous )
4873 Camera_desired_velocity.xyz.x = 0.0f;
4874 Camera_desired_velocity.xyz.y = 0.0f;
4875 Camera_desired_velocity.xyz.z = 0.0f;
4877 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4878 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4879 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4881 if ( instantaneous ) {
4882 Camera_velocity = Camera_desired_velocity;
4890 vector new_vel, delta_pos;
4892 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4893 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4894 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4896 Camera_velocity = new_vel;
4898 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4900 vm_vec_add2( &Camera_pos, &delta_pos );
4902 float ot = Camera_time+0.0f;
4904 Camera_time += flFrametime;
4906 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4909 tmp.xyz.z = 4.739f; // always go this fast forward.
4911 // pick x and y velocities so they are always on a
4912 // circle with a 25 m radius.
4914 float tmp_angle = frand()*PI2;
4916 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4917 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4919 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4921 //mprintf(( "Changing velocity!\n" ));
4922 camera_set_velocity( &tmp, 0 );
4925 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4926 vector tmp = ZERO_VECTOR;
4927 camera_set_velocity( &tmp, 0 );
4932 void end_demo_campaign_do()
4934 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4935 // show upsell screens
4936 demo_upsell_show_screens();
4937 #elif defined(OEM_BUILD)
4938 // show oem upsell screens
4939 oem_upsell_show_screens();
4942 // drop into main hall
4943 gameseq_post_event( GS_EVENT_MAIN_MENU );
4946 // All code to process events. This is the only place
4947 // that you should change the state of the game.
4948 void game_process_event( int current_state, int event )
4950 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4953 case GS_EVENT_SIMULATOR_ROOM:
4954 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4957 case GS_EVENT_MAIN_MENU:
4958 gameseq_set_state(GS_STATE_MAIN_MENU);
4961 case GS_EVENT_OPTIONS_MENU:
4962 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4965 case GS_EVENT_BARRACKS_MENU:
4966 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4969 case GS_EVENT_TECH_MENU:
4970 gameseq_set_state(GS_STATE_TECH_MENU);
4973 case GS_EVENT_TRAINING_MENU:
4974 gameseq_set_state(GS_STATE_TRAINING_MENU);
4977 case GS_EVENT_START_GAME:
4978 Select_default_ship = 0;
4979 Player_multi_died_check = -1;
4980 gameseq_set_state(GS_STATE_CMD_BRIEF);
4983 case GS_EVENT_START_BRIEFING:
4984 gameseq_set_state(GS_STATE_BRIEFING);
4987 case GS_EVENT_DEBRIEF:
4988 // did we end the campaign in the main freespace 2 single player campaign?
4990 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace")) {
4992 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace2")) {
4994 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4996 gameseq_set_state(GS_STATE_DEBRIEF);
4999 Player_multi_died_check = -1;
5002 case GS_EVENT_SHIP_SELECTION:
5003 gameseq_set_state( GS_STATE_SHIP_SELECT );
5006 case GS_EVENT_WEAPON_SELECTION:
5007 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5010 case GS_EVENT_ENTER_GAME:
5012 // maybe start recording a demo
5014 demo_start_record("test.fsd");
5018 if (Game_mode & GM_MULTIPLAYER) {
5019 // if we're respawning, make sure we change the view mode so that the hud shows up
5020 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5024 gameseq_set_state(GS_STATE_GAME_PLAY);
5026 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5029 Player_multi_died_check = -1;
5031 // clear multiplayer button info
5032 extern button_info Multi_ship_status_bi;
5033 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5035 Start_time = f2fl(timer_get_approx_seconds());
5037 mprintf(("Entering game at time = %7.3f\n", Start_time));
5041 case GS_EVENT_START_GAME_QUICK:
5042 Select_default_ship = 1;
5043 gameseq_post_event(GS_EVENT_ENTER_GAME);
5047 case GS_EVENT_END_GAME:
5048 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5049 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5050 gameseq_set_state(GS_STATE_MAIN_MENU);
5055 Player_multi_died_check = -1;
5058 case GS_EVENT_QUIT_GAME:
5059 main_hall_stop_music();
5060 main_hall_stop_ambient();
5061 gameseq_set_state(GS_STATE_QUIT_GAME);
5063 Player_multi_died_check = -1;
5066 case GS_EVENT_GAMEPLAY_HELP:
5067 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5070 case GS_EVENT_PAUSE_GAME:
5071 gameseq_push_state(GS_STATE_GAME_PAUSED);
5074 case GS_EVENT_DEBUG_PAUSE_GAME:
5075 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5078 case GS_EVENT_TRAINING_PAUSE:
5079 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5082 case GS_EVENT_PREVIOUS_STATE:
5083 gameseq_pop_state();
5086 case GS_EVENT_TOGGLE_FULLSCREEN:
5087 gr_toggle_fullscreen();
5090 case GS_EVENT_TOGGLE_GLIDE:
5093 case GS_EVENT_LOAD_MISSION_MENU:
5096 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5097 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5100 case GS_EVENT_HUD_CONFIG:
5101 gameseq_push_state( GS_STATE_HUD_CONFIG );
5104 case GS_EVENT_CONTROL_CONFIG:
5105 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5108 case GS_EVENT_DEATH_DIED:
5109 gameseq_set_state( GS_STATE_DEATH_DIED );
5112 case GS_EVENT_DEATH_BLEW_UP:
5113 if ( current_state == GS_STATE_DEATH_DIED ) {
5114 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5115 event_music_player_death();
5117 // multiplayer clients set their extra check here
5118 if(Game_mode & GM_MULTIPLAYER){
5119 // set the multi died absolute last chance check
5120 Player_multi_died_check = time(NULL);
5123 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5127 case GS_EVENT_NEW_CAMPAIGN:
5128 if (!mission_load_up_campaign()){
5129 readyroom_continue_campaign();
5132 Player_multi_died_check = -1;
5135 case GS_EVENT_CAMPAIGN_CHEAT:
5136 if (!mission_load_up_campaign()){
5138 // bash campaign value
5139 extern char Main_hall_campaign_cheat[512];
5142 // look for the mission
5143 for(idx=0; idx<Campaign.num_missions; idx++){
5144 if(!SDL_strcasecmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5145 Campaign.next_mission = idx;
5146 Campaign.prev_mission = idx - 1;
5153 readyroom_continue_campaign();
5156 Player_multi_died_check = -1;
5159 case GS_EVENT_CAMPAIGN_ROOM:
5160 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5163 case GS_EVENT_CMD_BRIEF:
5164 gameseq_set_state(GS_STATE_CMD_BRIEF);
5167 case GS_EVENT_RED_ALERT:
5168 gameseq_set_state(GS_STATE_RED_ALERT);
5171 case GS_EVENT_CREDITS:
5172 gameseq_set_state( GS_STATE_CREDITS );
5175 case GS_EVENT_VIEW_MEDALS:
5176 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5179 case GS_EVENT_SHOW_GOALS:
5180 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5183 case GS_EVENT_HOTKEY_SCREEN:
5184 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5187 // multiplayer stuff follow these comments
5189 case GS_EVENT_MULTI_JOIN_GAME:
5190 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5193 case GS_EVENT_MULTI_HOST_SETUP:
5194 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5197 case GS_EVENT_MULTI_CLIENT_SETUP:
5198 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5201 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5202 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5205 case GS_EVENT_MULTI_STD_WAIT:
5206 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5209 case GS_EVENT_STANDALONE_MAIN:
5210 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5213 case GS_EVENT_MULTI_PAUSE:
5214 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5217 case GS_EVENT_INGAME_PRE_JOIN:
5218 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5221 case GS_EVENT_EVENT_DEBUG:
5222 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5225 // Start a warpout where player automatically goes 70 no matter what
5226 // and can't cancel out of it.
5227 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5228 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5230 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5231 Player->saved_viewer_mode = Viewer_mode;
5232 Player->control_mode = PCM_WARPOUT_STAGE1;
5233 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5234 Warpout_time = 0.0f; // Start timer!
5237 case GS_EVENT_PLAYER_WARPOUT_START:
5238 if ( Player->control_mode != PCM_NORMAL ) {
5239 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5241 Player->saved_viewer_mode = Viewer_mode;
5242 Player->control_mode = PCM_WARPOUT_STAGE1;
5243 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5244 Warpout_time = 0.0f; // Start timer!
5245 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5249 case GS_EVENT_PLAYER_WARPOUT_STOP:
5250 if ( Player->control_mode != PCM_NORMAL ) {
5251 if ( !Warpout_forced ) { // cannot cancel forced warpout
5252 Player->control_mode = PCM_NORMAL;
5253 Viewer_mode = Player->saved_viewer_mode;
5254 hud_subspace_notify_abort();
5255 mprintf(( "Player put back to normal mode.\n" ));
5256 if ( Warpout_sound > -1 ) {
5257 snd_stop( Warpout_sound );
5264 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5265 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5266 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5267 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5269 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5270 shipfx_warpout_start( Player_obj );
5271 Player->control_mode = PCM_WARPOUT_STAGE2;
5272 Player->saved_viewer_mode = Viewer_mode;
5273 Viewer_mode |= VM_WARP_CHASE;
5275 vector tmp = Player_obj->pos;
5277 ship_get_eye( &tmp, &tmp_m, Player_obj );
5278 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5279 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5280 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5282 camera_set_position( &tmp );
5283 camera_set_orient( &Player_obj->orient );
5284 vector tmp_vel = { { { 0.0f, 5.1919f, 14.7f } } };
5286 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5287 camera_set_velocity( &tmp_vel, 1);
5291 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5292 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5293 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5294 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5296 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5297 Player->control_mode = PCM_WARPOUT_STAGE3;
5301 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5302 mprintf(( "Player warped out. Going to debriefing!\n" ));
5303 Player->control_mode = PCM_NORMAL;
5304 Viewer_mode = Player->saved_viewer_mode;
5307 // we have a special debriefing screen for multiplayer furballs
5308 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5309 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5311 // do the normal debriefing for all other situations
5313 gameseq_post_event(GS_EVENT_DEBRIEF);
5317 case GS_EVENT_STANDALONE_POSTGAME:
5318 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5321 case GS_EVENT_INITIAL_PLAYER_SELECT:
5322 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5325 case GS_EVENT_GAME_INIT:
5326 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5327 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5329 // see if the command line option has been set to use the last pilot, and act acoordingly
5330 if( player_select_get_last_pilot() ) {
5331 // always enter the main menu -- do the automatic network startup stuff elsewhere
5332 // so that we still have valid checks for networking modes, etc.
5333 gameseq_set_state(GS_STATE_MAIN_MENU);
5335 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5340 case GS_EVENT_MULTI_MISSION_SYNC:
5341 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5344 case GS_EVENT_MULTI_START_GAME:
5345 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5348 case GS_EVENT_MULTI_HOST_OPTIONS:
5349 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5352 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5353 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5356 case GS_EVENT_TEAM_SELECT:
5357 gameseq_set_state(GS_STATE_TEAM_SELECT);
5360 case GS_EVENT_END_CAMPAIGN:
5361 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5364 case GS_EVENT_END_DEMO:
5365 gameseq_set_state(GS_STATE_END_DEMO);
5368 case GS_EVENT_LOOP_BRIEF:
5369 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5378 // Called when a state is being left.
5379 // The current state is still at old_state, but as soon as
5380 // this function leaves, then the current state will become
5381 // new state. You should never try to change the state
5382 // in here... if you think you need to, you probably really
5383 // need to post an event, not change the state.
5384 void game_leave_state( int old_state, int new_state )
5386 int end_mission = 1;
5388 switch (new_state) {
5389 case GS_STATE_GAME_PAUSED:
5390 case GS_STATE_DEBUG_PAUSED:
5391 case GS_STATE_OPTIONS_MENU:
5392 case GS_STATE_CONTROL_CONFIG:
5393 case GS_STATE_MISSION_LOG_SCROLLBACK:
5394 case GS_STATE_DEATH_DIED:
5395 case GS_STATE_SHOW_GOALS:
5396 case GS_STATE_HOTKEY_SCREEN:
5397 case GS_STATE_MULTI_PAUSED:
5398 case GS_STATE_TRAINING_PAUSED:
5399 case GS_STATE_EVENT_DEBUG:
5400 case GS_STATE_GAMEPLAY_HELP:
5401 end_mission = 0; // these events shouldn't end a mission
5405 switch (old_state) {
5406 case GS_STATE_BRIEFING:
5407 brief_stop_voices();
5408 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5409 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5410 && (new_state != GS_STATE_TEAM_SELECT) ){
5411 common_select_close();
5412 if ( new_state == GS_STATE_MAIN_MENU ) {
5413 freespace_stop_mission();
5417 // COMMAND LINE OPTION
5418 if (Cmdline_multi_stream_chat_to_file){
5419 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5420 cfclose(Multi_chat_stream);
5424 case GS_STATE_DEBRIEF:
5425 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5430 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5431 multi_df_debrief_close();
5434 case GS_STATE_LOAD_MISSION_MENU:
5437 case GS_STATE_SIMULATOR_ROOM:
5441 case GS_STATE_CAMPAIGN_ROOM:
5442 campaign_room_close();
5445 case GS_STATE_CMD_BRIEF:
5446 if (new_state == GS_STATE_OPTIONS_MENU) {
5451 if (new_state == GS_STATE_MAIN_MENU)
5452 freespace_stop_mission();
5457 case GS_STATE_RED_ALERT:
5461 case GS_STATE_SHIP_SELECT:
5462 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5463 new_state != GS_STATE_HOTKEY_SCREEN &&
5464 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5465 common_select_close();
5466 if ( new_state == GS_STATE_MAIN_MENU ) {
5467 freespace_stop_mission();
5472 case GS_STATE_WEAPON_SELECT:
5473 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5474 new_state != GS_STATE_HOTKEY_SCREEN &&
5475 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5476 common_select_close();
5477 if ( new_state == GS_STATE_MAIN_MENU ) {
5478 freespace_stop_mission();
5483 case GS_STATE_TEAM_SELECT:
5484 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5485 new_state != GS_STATE_HOTKEY_SCREEN &&
5486 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5487 common_select_close();
5488 if ( new_state == GS_STATE_MAIN_MENU ) {
5489 freespace_stop_mission();
5494 case GS_STATE_MAIN_MENU:
5495 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5502 case GS_STATE_OPTIONS_MENU:
5503 //game_start_time();
5504 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5505 multi_join_clear_game_list();
5507 options_menu_close();
5510 case GS_STATE_BARRACKS_MENU:
5511 if(new_state != GS_STATE_VIEW_MEDALS){
5516 case GS_STATE_MISSION_LOG_SCROLLBACK:
5517 hud_scrollback_close();
5520 case GS_STATE_TRAINING_MENU:
5521 training_menu_close();
5524 case GS_STATE_GAME_PLAY:
5525 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5526 player_save_target_and_weapon_link_prefs();
5527 game_stop_looped_sounds();
5530 sound_env_disable();
5531 joy_ff_stop_effects();
5533 // stop game time under certain conditions
5534 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5539 // shut down any recording or playing demos
5544 // when in multiplayer and going back to the main menu, send a leave game packet
5545 // right away (before calling stop mission). stop_mission was taking to long to
5546 // close mission down and I want people to get notified ASAP.
5547 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5548 multi_quit_game(PROMPT_NONE);
5551 freespace_stop_mission();
5552 Game_time_compression = F1_0;
5556 case GS_STATE_TECH_MENU:
5560 case GS_STATE_TRAINING_PAUSED:
5561 Training_num_lines = 0;
5562 // fall through to GS_STATE_GAME_PAUSED
5564 case GS_STATE_GAME_PAUSED:
5566 if ( end_mission ) {
5571 case GS_STATE_DEBUG_PAUSED:
5574 pause_debug_close();
5578 case GS_STATE_HUD_CONFIG:
5582 // join/start a game
5583 case GS_STATE_MULTI_JOIN_GAME:
5584 if(new_state != GS_STATE_OPTIONS_MENU){
5585 multi_join_game_close();
5589 case GS_STATE_MULTI_HOST_SETUP:
5590 case GS_STATE_MULTI_CLIENT_SETUP:
5591 // if this is just the host going into the options screen, don't do anything
5592 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5596 // close down the proper state
5597 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5598 multi_create_game_close();
5600 multi_game_client_setup_close();
5603 // COMMAND LINE OPTION
5604 if (Cmdline_multi_stream_chat_to_file){
5605 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5606 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5607 cfclose(Multi_chat_stream);
5612 case GS_STATE_CONTROL_CONFIG:
5613 control_config_close();
5616 case GS_STATE_DEATH_DIED:
5617 Game_mode &= ~GM_DEAD_DIED;
5619 // early end while respawning or blowing up in a multiplayer game
5620 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5622 freespace_stop_mission();
5626 case GS_STATE_DEATH_BLEW_UP:
5627 Game_mode &= ~GM_DEAD_BLEW_UP;
5629 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5630 // to determine if I should do anything.
5631 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5633 freespace_stop_mission();
5636 // if we are not respawing as an observer or as a player, our new state will not
5637 // be gameplay state.
5638 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5639 game_stop_time(); // hasn't been called yet!!
5640 freespace_stop_mission();
5646 case GS_STATE_CREDITS:
5650 case GS_STATE_VIEW_MEDALS:
5654 case GS_STATE_SHOW_GOALS:
5655 mission_show_goals_close();
5658 case GS_STATE_HOTKEY_SCREEN:
5659 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5660 mission_hotkey_close();
5664 case GS_STATE_MULTI_MISSION_SYNC:
5665 // if we're moving into the options menu, don't do anything
5666 if(new_state == GS_STATE_OPTIONS_MENU){
5670 SDL_assert( Game_mode & GM_MULTIPLAYER );
5672 if ( new_state == GS_STATE_GAME_PLAY ){
5673 // palette_restore_palette();
5675 // change a couple of flags to indicate our state!!!
5676 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5677 send_netplayer_update_packet();
5679 // set the game mode
5680 Game_mode |= GM_IN_MISSION;
5684 case GS_STATE_VIEW_CUTSCENES:
5685 cutscenes_screen_close();
5688 case GS_STATE_MULTI_STD_WAIT:
5689 multi_standalone_wait_close();
5692 case GS_STATE_STANDALONE_MAIN:
5693 standalone_main_close();
5694 if(new_state == GS_STATE_MULTI_STD_WAIT){
5695 init_multiplayer_stats();
5699 case GS_STATE_MULTI_PAUSED:
5700 // if ( end_mission ){
5705 case GS_STATE_INGAME_PRE_JOIN:
5706 multi_ingame_select_close();
5709 case GS_STATE_STANDALONE_POSTGAME:
5710 multi_standalone_postgame_close();
5713 case GS_STATE_INITIAL_PLAYER_SELECT:
5714 player_select_close();
5717 case GS_STATE_MULTI_START_GAME:
5718 multi_start_game_close();
5721 case GS_STATE_MULTI_HOST_OPTIONS:
5722 multi_host_options_close();
5725 case GS_STATE_END_OF_CAMPAIGN:
5726 mission_campaign_end_close();
5729 case GS_STATE_LOOP_BRIEF:
5735 // Called when a state is being entered.
5736 // The current state is set to the state we're entering at
5737 // this point, and old_state is set to the state we're coming
5738 // from. You should never try to change the state
5739 // in here... if you think you need to, you probably really
5740 // need to post an event, not change the state.
5742 void game_enter_state( int old_state, int new_state )
5744 switch (new_state) {
5745 case GS_STATE_MAIN_MENU:
5746 // in multiplayer mode, be sure that we are not doing networking anymore.
5747 if ( Game_mode & GM_MULTIPLAYER ) {
5748 SDL_assert( Net_player != NULL );
5749 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5752 Game_time_compression = F1_0;
5754 // determine which ship this guy is currently based on
5755 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5758 if (Player->on_bastion) {
5766 case GS_STATE_BRIEFING:
5767 main_hall_stop_music();
5768 main_hall_stop_ambient();
5770 if (Game_mode & GM_NORMAL) {
5771 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5772 // MWA: or from options or hotkey screens
5773 // JH: or if the command brief state already did this
5774 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5775 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5776 && (old_state != GS_STATE_CMD_BRIEF) ) {
5777 if ( !game_start_mission() ) // this should put us into a new state on failure!
5781 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5782 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5783 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5785 Game_time_compression = F1_0;
5787 if ( red_alert_mission() ) {
5788 gameseq_post_event(GS_EVENT_RED_ALERT);
5795 case GS_STATE_DEBRIEF:
5796 game_stop_looped_sounds();
5797 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5798 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5803 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5804 multi_df_debrief_init();
5807 case GS_STATE_LOAD_MISSION_MENU:
5810 case GS_STATE_SIMULATOR_ROOM:
5814 case GS_STATE_CAMPAIGN_ROOM:
5815 campaign_room_init();
5818 case GS_STATE_RED_ALERT:
5819 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5823 case GS_STATE_CMD_BRIEF: {
5824 int team_num = 0; // team number used as index for which cmd brief to use.
5826 if (old_state == GS_STATE_OPTIONS_MENU) {
5830 main_hall_stop_music();
5831 main_hall_stop_ambient();
5833 if (Game_mode & GM_NORMAL) {
5834 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5835 // MWA: or from options or hotkey screens
5836 // JH: or if the command brief state already did this
5837 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5838 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5839 if ( !game_start_mission() ) // this should put us into a new state on failure!
5844 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5845 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5846 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5848 cmd_brief_init(team_num);
5854 case GS_STATE_SHIP_SELECT:
5858 case GS_STATE_WEAPON_SELECT:
5859 weapon_select_init();
5862 case GS_STATE_TEAM_SELECT:
5866 case GS_STATE_GAME_PAUSED:
5871 case GS_STATE_DEBUG_PAUSED:
5872 // game_stop_time();
5873 // os_set_title("FreeSpace - PAUSED");
5876 case GS_STATE_TRAINING_PAUSED:
5883 case GS_STATE_OPTIONS_MENU:
5885 options_menu_init();
5888 case GS_STATE_GAME_PLAY:
5889 // coming from the gameplay state or the main menu, we might need to load the mission
5890 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5891 if ( !game_start_mission() ) // this should put us into a new state.
5896 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5897 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5898 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5899 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5900 (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)) ) {
5901 // JAS: Used to do all paging here.
5905 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5909 main_hall_stop_music();
5910 main_hall_stop_ambient();
5911 event_music_first_pattern(); // start the first pattern
5914 // special code that restores player ship selection and weapons loadout when doing a quick start
5915 if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY)) ) {
5916 if ( !SDL_strcasecmp(Player_loadout.filename, Game_current_mission_filename) ) {
5917 wss_direct_restore_loadout();
5921 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5922 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5923 event_music_first_pattern(); // start the first pattern
5926 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5927 event_music_first_pattern(); // start the first pattern
5929 player_restore_target_and_weapon_link_prefs();
5931 Game_mode |= GM_IN_MISSION;
5934 // required to truely make mouse deltas zeroed in debug mouse code
5935 void mouse_force_pos(int x, int y);
5936 if (!Is_standalone) {
5937 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5943 // only start time if in single player, or coming from multi wait state
5946 (Game_mode & GM_NORMAL) &&
5947 (old_state != GS_STATE_VIEW_CUTSCENES)
5949 (Game_mode & GM_MULTIPLAYER) && (
5950 (old_state == GS_STATE_MULTI_PAUSED) ||
5951 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5957 // when coming from the multi paused state, reset the timestamps
5958 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5959 multi_reset_timestamps();
5962 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5963 // initialize all object update details
5964 multi_oo_gameplay_init();
5967 // under certain circumstances, the server should reset the object update rate limiting stuff
5968 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5969 ((old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC)) ){
5971 // reinitialize the rate limiting system for all clients
5972 multi_oo_rate_init_all();
5975 // multiplayer clients should always re-initialize their control info rate limiting system
5976 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5977 multi_oo_rate_init_all();
5981 if(Game_mode & GM_MULTIPLAYER){
5982 multi_ping_reset_players();
5985 Game_subspace_effect = 0;
5986 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5987 Game_subspace_effect = 1;
5988 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5989 game_start_subspace_ambient_sound();
5993 sound_env_set(&Game_sound_env);
5994 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5996 // clear multiplayer button info i
5997 extern button_info Multi_ship_status_bi;
5998 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6001 case GS_STATE_HUD_CONFIG:
6005 case GS_STATE_MULTI_JOIN_GAME:
6006 multi_join_clear_game_list();
6008 if (old_state != GS_STATE_OPTIONS_MENU) {
6009 multi_join_game_init();
6014 case GS_STATE_MULTI_HOST_SETUP:
6015 // don't reinitialize if we're coming back from the host options screen
6016 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6017 multi_create_game_init();
6022 case GS_STATE_MULTI_CLIENT_SETUP:
6023 if (old_state != GS_STATE_OPTIONS_MENU) {
6024 multi_game_client_setup_init();
6029 case GS_STATE_CONTROL_CONFIG:
6030 control_config_init();
6033 case GS_STATE_TECH_MENU:
6037 case GS_STATE_BARRACKS_MENU:
6038 if(old_state != GS_STATE_VIEW_MEDALS){
6043 case GS_STATE_MISSION_LOG_SCROLLBACK:
6044 hud_scrollback_init();
6047 case GS_STATE_DEATH_DIED:
6048 Player_died_time = timestamp(10);
6050 if(!(Game_mode & GM_MULTIPLAYER)){
6051 player_show_death_message();
6053 Game_mode |= GM_DEAD_DIED;
6056 case GS_STATE_DEATH_BLEW_UP:
6057 if ( !popupdead_is_active() ) {
6058 Player_ai->target_objnum = -1;
6061 // stop any local EMP effect
6064 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6065 Game_mode |= GM_DEAD_BLEW_UP;
6066 Show_viewing_from_self = 0;
6068 // timestamp how long we should wait before displaying the died popup
6069 if ( !popupdead_is_active() ) {
6070 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6074 case GS_STATE_GAMEPLAY_HELP:
6075 gameplay_help_init();
6078 case GS_STATE_CREDITS:
6079 main_hall_stop_music();
6080 main_hall_stop_ambient();
6084 case GS_STATE_VIEW_MEDALS:
6085 medal_main_init(Player);
6088 case GS_STATE_SHOW_GOALS:
6089 mission_show_goals_init();
6092 case GS_STATE_HOTKEY_SCREEN:
6093 mission_hotkey_init();
6096 case GS_STATE_MULTI_MISSION_SYNC:
6097 // if we're coming from the options screen, don't do any
6098 if(old_state == GS_STATE_OPTIONS_MENU){
6102 switch(Multi_sync_mode){
6103 case MULTI_SYNC_PRE_BRIEFING:
6104 // if moving from game forming to the team select state
6107 case MULTI_SYNC_POST_BRIEFING:
6108 // if moving from briefing into the mission itself
6111 // tell everyone that we're now loading data
6112 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6113 send_netplayer_update_packet();
6115 // JAS: Used to do all paging here!!!!
6117 Net_player->state = NETPLAYER_STATE_WAITING;
6118 send_netplayer_update_packet();
6120 Game_time_compression = F1_0;
6122 case MULTI_SYNC_INGAME:
6128 case GS_STATE_VIEW_CUTSCENES:
6129 cutscenes_screen_init();
6132 case GS_STATE_MULTI_STD_WAIT:
6133 multi_standalone_wait_init();
6136 case GS_STATE_STANDALONE_MAIN:
6137 // don't initialize if we're coming from one of these 2 states unless there are no
6138 // players left (reset situation)
6139 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6140 standalone_main_init();
6144 case GS_STATE_MULTI_PAUSED:
6148 case GS_STATE_INGAME_PRE_JOIN:
6149 multi_ingame_select_init();
6152 case GS_STATE_STANDALONE_POSTGAME:
6153 multi_standalone_postgame_init();
6156 case GS_STATE_INITIAL_PLAYER_SELECT:
6157 player_select_init();
6160 case GS_STATE_MULTI_START_GAME:
6161 multi_start_game_init();
6164 case GS_STATE_MULTI_HOST_OPTIONS:
6165 multi_host_options_init();
6168 case GS_STATE_END_OF_CAMPAIGN:
6169 mission_campaign_end_init();
6172 case GS_STATE_LOOP_BRIEF:
6179 // do stuff that may need to be done regardless of state
6180 void game_do_state_common(int state,int no_networking)
6182 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6183 snd_do_frame(); // update sound system
6184 event_music_do_frame(); // music needs to play across many states
6186 multi_log_process();
6188 if (no_networking) {
6192 // maybe do a multiplayer frame based on game mode and state type
6193 if (Game_mode & GM_MULTIPLAYER) {
6195 case GS_STATE_OPTIONS_MENU:
6196 case GS_STATE_GAMEPLAY_HELP:
6197 case GS_STATE_HOTKEY_SCREEN:
6198 case GS_STATE_HUD_CONFIG:
6199 case GS_STATE_CONTROL_CONFIG:
6200 case GS_STATE_MISSION_LOG_SCROLLBACK:
6201 case GS_STATE_SHOW_GOALS:
6202 case GS_STATE_VIEW_CUTSCENES:
6203 case GS_STATE_EVENT_DEBUG:
6204 multi_maybe_do_frame();
6208 game_do_networking();
6212 // Called once a frame.
6213 // You should never try to change the state
6214 // in here... if you think you need to, you probably really
6215 // need to post an event, not change the state.
6216 int Game_do_state_should_skip = 0;
6217 void game_do_state(int state)
6219 // always lets the do_state_common() function determine if the state should be skipped
6220 Game_do_state_should_skip = 0;
6222 // legal to set the should skip state anywhere in this function
6223 game_do_state_common(state); // do stuff that may need to be done regardless of state
6225 if(Game_do_state_should_skip){
6230 case GS_STATE_MAIN_MENU:
6231 game_set_frametime(GS_STATE_MAIN_MENU);
6232 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6235 main_hall_do(flFrametime);
6239 case GS_STATE_OPTIONS_MENU:
6240 game_set_frametime(GS_STATE_OPTIONS_MENU);
6241 options_menu_do_frame(flFrametime);
6244 case GS_STATE_BARRACKS_MENU:
6245 game_set_frametime(GS_STATE_BARRACKS_MENU);
6246 barracks_do_frame(flFrametime);
6249 case GS_STATE_TRAINING_MENU:
6250 game_set_frametime(GS_STATE_TRAINING_MENU);
6251 training_menu_do_frame(flFrametime);
6254 case GS_STATE_TECH_MENU:
6255 game_set_frametime(GS_STATE_TECH_MENU);
6256 techroom_do_frame(flFrametime);
6259 case GS_STATE_GAMEPLAY_HELP:
6260 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6261 gameplay_help_do_frame(flFrametime);
6264 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6268 case GS_STATE_GAME_PAUSED:
6272 case GS_STATE_DEBUG_PAUSED:
6274 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6279 case GS_STATE_TRAINING_PAUSED:
6280 game_training_pause_do();
6283 case GS_STATE_LOAD_MISSION_MENU:
6287 case GS_STATE_BRIEFING:
6288 game_set_frametime(GS_STATE_BRIEFING);
6289 brief_do_frame(flFrametime);
6292 case GS_STATE_DEBRIEF:
6293 game_set_frametime(GS_STATE_DEBRIEF);
6294 debrief_do_frame(flFrametime);
6297 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6298 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6299 multi_df_debrief_do();
6302 case GS_STATE_SHIP_SELECT:
6303 game_set_frametime(GS_STATE_SHIP_SELECT);
6304 ship_select_do(flFrametime);
6307 case GS_STATE_WEAPON_SELECT:
6308 game_set_frametime(GS_STATE_WEAPON_SELECT);
6309 weapon_select_do(flFrametime);
6312 case GS_STATE_MISSION_LOG_SCROLLBACK:
6313 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6314 hud_scrollback_do_frame(flFrametime);
6317 case GS_STATE_HUD_CONFIG:
6318 game_set_frametime(GS_STATE_HUD_CONFIG);
6319 hud_config_do_frame(flFrametime);
6322 case GS_STATE_MULTI_JOIN_GAME:
6323 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6324 multi_join_game_do_frame();
6327 case GS_STATE_MULTI_HOST_SETUP:
6328 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6329 multi_create_game_do();
6332 case GS_STATE_MULTI_CLIENT_SETUP:
6333 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6334 multi_game_client_setup_do_frame();
6337 case GS_STATE_CONTROL_CONFIG:
6338 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6339 control_config_do_frame(flFrametime);
6342 case GS_STATE_DEATH_DIED:
6346 case GS_STATE_DEATH_BLEW_UP:
6350 case GS_STATE_SIMULATOR_ROOM:
6351 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6352 sim_room_do_frame(flFrametime);
6355 case GS_STATE_CAMPAIGN_ROOM:
6356 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6357 campaign_room_do_frame(flFrametime);
6360 case GS_STATE_RED_ALERT:
6361 game_set_frametime(GS_STATE_RED_ALERT);
6362 red_alert_do_frame(flFrametime);
6365 case GS_STATE_CMD_BRIEF:
6366 game_set_frametime(GS_STATE_CMD_BRIEF);
6367 cmd_brief_do_frame(flFrametime);
6370 case GS_STATE_CREDITS:
6371 game_set_frametime(GS_STATE_CREDITS);
6372 credits_do_frame(flFrametime);
6375 case GS_STATE_VIEW_MEDALS:
6376 game_set_frametime(GS_STATE_VIEW_MEDALS);
6380 case GS_STATE_SHOW_GOALS:
6381 game_set_frametime(GS_STATE_SHOW_GOALS);
6382 mission_show_goals_do_frame(flFrametime);
6385 case GS_STATE_HOTKEY_SCREEN:
6386 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6387 mission_hotkey_do_frame(flFrametime);
6390 case GS_STATE_VIEW_CUTSCENES:
6391 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6392 cutscenes_screen_do_frame();
6395 case GS_STATE_MULTI_STD_WAIT:
6396 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6397 multi_standalone_wait_do();
6400 case GS_STATE_STANDALONE_MAIN:
6401 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6402 standalone_main_do();
6405 case GS_STATE_MULTI_PAUSED:
6406 game_set_frametime(GS_STATE_MULTI_PAUSED);
6410 case GS_STATE_TEAM_SELECT:
6411 game_set_frametime(GS_STATE_TEAM_SELECT);
6415 case GS_STATE_INGAME_PRE_JOIN:
6416 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6417 multi_ingame_select_do();
6420 case GS_STATE_EVENT_DEBUG:
6422 game_set_frametime(GS_STATE_EVENT_DEBUG);
6423 game_show_event_debug(flFrametime);
6427 case GS_STATE_STANDALONE_POSTGAME:
6428 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6429 multi_standalone_postgame_do();
6432 case GS_STATE_INITIAL_PLAYER_SELECT:
6433 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6437 case GS_STATE_MULTI_MISSION_SYNC:
6438 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6442 case GS_STATE_MULTI_START_GAME:
6443 game_set_frametime(GS_STATE_MULTI_START_GAME);
6444 multi_start_game_do();
6447 case GS_STATE_MULTI_HOST_OPTIONS:
6448 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6449 multi_host_options_do();
6452 case GS_STATE_END_OF_CAMPAIGN:
6453 mission_campaign_end_do();
6456 case GS_STATE_END_DEMO:
6457 game_set_frametime(GS_STATE_END_DEMO);
6458 end_demo_campaign_do();
6461 case GS_STATE_LOOP_BRIEF:
6462 game_set_frametime(GS_STATE_LOOP_BRIEF);
6466 } // end switch(gs_current_state)
6470 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6471 int game_do_ram_check(int ram_in_mbytes)
6473 if ( ram_in_mbytes < 30 ) {
6474 int allowed_to_run = 1;
6475 if ( ram_in_mbytes < 25 ) {
6481 if ( allowed_to_run ) {
6482 SDL_MessageBoxData mboxd;
6483 SDL_MessageBoxButtonData mboxbuttons[2];
6486 // not a translated string, but it's too long and smartdrv isn't
6487 // really a thing for any OS we now support :p
6488 // 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);
6489 SDL_snprintf( tmp, sizeof(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);
6491 mboxbuttons[0].buttonid = 0;
6492 mboxbuttons[0].text = XSTR("Ok", 503);
6493 mboxbuttons[0].flags = 0;
6495 mboxbuttons[1].buttonid = 1;
6496 mboxbuttons[1].text = XSTR("Cancel", 504);
6497 mboxbuttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
6499 mboxd.flags = SDL_MESSAGEBOX_ERROR;
6500 mboxd.title = XSTR( "Not Enough RAM", 194);
6501 mboxd.message = tmp;
6502 mboxd.numbuttons = 2;
6503 mboxd.buttons = mboxbuttons;
6504 mboxd.window = NULL;
6505 mboxd.colorScheme = NULL;
6507 SDL_ShowMessageBox(&mboxd, &msgbox_rval);
6509 if ( msgbox_rval == 1 ) {
6513 // not a translated string, but it's too long and smartdrv isn't
6514 // really a thing for any OS we now support :p
6515 // 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);
6516 SDL_snprintf( tmp, sizeof(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);
6518 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough RAM", 194), tmp, NULL);
6527 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6528 // If so, copy it over and remove the update directory.
6529 void game_maybe_update_launcher(char *exe_dir)
6534 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6538 int sub_total_destroyed = 0;
6542 // get the total for all his children
6543 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6544 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6547 // find the # of faces for this _individual_ object
6548 total = submodel_get_num_polys(model_num, sm);
6549 if(strstr(pm->submodel[sm].name, "-destroyed")){
6550 sub_total_destroyed = total;
6554 SDL_snprintf(str, sizeof(str), "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6557 *out_total += total + sub_total;
6558 *out_destroyed_total += sub_total_destroyed;
6561 #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);
6562 void game_spew_pof_info()
6564 char *pof_list[1000];
6567 int idx, model_num, i, j;
6569 int total, root_total, model_total, destroyed_total, counted;
6573 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6575 // spew info on all the pofs
6581 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6586 for(idx=0; idx<num_files; idx++, counted++){
6587 SDL_snprintf(str, sizeof(str), "%s.pof", pof_list[idx]);
6588 model_num = model_load(str, 0, NULL);
6590 pm = model_get(model_num);
6592 // if we have a real model
6597 // go through and print all raw submodels
6598 cfputs("RAW\n", out);
6601 for (i=0; i<pm->n_models; i++) {
6602 total = submodel_get_num_polys(model_num, i);
6604 model_total += total;
6605 SDL_snprintf(str, sizeof(str), "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6608 SDL_snprintf(str, sizeof(str), "Model total %d\n", model_total);
6611 // now go through and do it by LOD
6612 cfputs("BY LOD\n\n", out);
6613 for(i=0; i<pm->n_detail_levels; i++){
6614 SDL_snprintf(str, sizeof(str), "LOD %d\n", i);
6618 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6620 destroyed_total = 0;
6621 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6622 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6625 SDL_snprintf(str, sizeof(str), "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6628 SDL_snprintf(str, sizeof(str), "TOTAL: %d\n", total + root_total);
6630 SDL_snprintf(str, sizeof(str), "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6632 SDL_snprintf(str, sizeof(str), "TOTAL destroyed faces %d\n\n", destroyed_total);
6635 cfputs("------------------------------------------------------------------------\n\n", out);
6639 if(counted >= MAX_POLYGON_MODELS - 5){
6652 game_spew_pof_info();
6655 int game_main(const char *szCmdLine)
6659 // Find out how much RAM is on this machine
6660 Freespace_total_ram = SDL_GetSystemRAM();
6662 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6666 if (!vm_init(24*1024*1024)) {
6667 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);
6671 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6673 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);
6682 extern void windebug_memwatch_init();
6683 windebug_memwatch_init();
6691 int cpu_cores = SDL_GetCPUCount();
6692 int le = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
6694 mprintf(("Platform: %s\n", SDL_GetPlatform()));
6695 mprintf(("CPU: %d %s\n", cpu_cores, (cpu_cores == 1) ? "core" : "cores"));
6696 mprintf(("Memory: %dMB\n", Freespace_total_ram));
6697 mprintf(("Build: %d-bit, %s-endian\n", sizeof(void*) * 8, le ? "little" : "big"));
6699 parse_cmdline(szCmdLine);
6701 mprintf(("--------------------------------------------------------------------------------\n"));
6703 #ifdef STANDALONE_ONLY_BUILD
6705 nprintf(("Network", "Standalone running"));
6708 nprintf(("Network", "Standalone running"));
6715 // maybe spew pof stuff
6716 if(Cmdline_spew_pof_info){
6717 game_spew_pof_info();
6722 // non-demo, non-standalone, play the intro movie
6724 if ( !Is_standalone ) {
6726 // release -- movies always play
6729 // 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
6730 movie_play( NOX("intro.mve") );
6732 // debug version, movie will only play with -showmovies
6733 #elif !defined(NDEBUG)
6735 movie_play( NOX("intro.mve") );
6738 if ( Cmdline_show_movies )
6739 movie_play( NOX("intro.mve") );
6748 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6750 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6754 // only important for non THREADED mode
6757 state = gameseq_process_events();
6758 if ( state == GS_STATE_QUIT_GAME ){
6763 #if defined(FS2_DEMO) || defined(FS1_DEMO)
6765 demo_upsell_show_screens();
6767 #elif defined(OEM_BUILD)
6768 // show upsell screens on exit
6769 oem_upsell_show_screens();
6776 // launcher the fslauncher program on exit
6777 void game_launch_launcher_on_exit()
6785 // This function is called when FreeSpace terminates normally.
6787 void game_shutdown(void)
6789 // don't ever flip a page on the standalone!
6790 if(!(Game_mode & GM_STANDALONE_SERVER)){
6796 // if the player has left the "player select" screen and quit the game without actually choosing
6797 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6798 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6802 // load up common multiplayer icons
6803 multi_unload_common_icons();
6805 shockwave_close(); // release any memory used by shockwave system
6806 fireball_close(); // free fireball system
6807 ship_close(); // free any memory that was allocated for the ships
6808 weapon_close(); // free any memory that was allocated for the weapons
6809 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6810 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6811 bm_unload_all(); // free bitmaps
6812 mission_campaign_close(); // close out the campaign stuff
6813 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
6814 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6816 #ifdef MULTI_USE_LAG
6820 // the menu close functions will unload the bitmaps if they were displayed during the game
6821 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6824 context_help_close(); // close out help system
6825 training_menu_close();
6826 lcl_close(); // be sure localization is closed out
6829 // free left-over memory from parsed tables
6830 cutscene_tbl_close();
6832 scoring_tbl_close();
6833 player_tips_close();
6835 extern void joy_close();
6838 audiostream_close();
6840 event_music_close();
6844 // HACKITY HACK HACK
6845 // if this flag is set, we should be firing up the launcher when exiting freespace
6846 extern int Multi_update_fireup_launcher_on_exit;
6847 if(Multi_update_fireup_launcher_on_exit){
6848 game_launch_launcher_on_exit();
6852 // game_stop_looped_sounds()
6854 // This function will call the appropriate stop looped sound functions for those
6855 // modules which use looping sounds. It is not enough just to stop a looping sound
6856 // at the DirectSound level, the game is keeping track of looping sounds, and this
6857 // function is used to inform the game that looping sounds are being halted.
6859 void game_stop_looped_sounds()
6861 hud_stop_looped_locking_sounds();
6862 hud_stop_looped_engine_sounds();
6863 afterburner_stop_sounds();
6864 player_stop_looped_sounds();
6865 obj_snd_stop_all(); // stop all object-linked persistant sounds
6866 game_stop_subspace_ambient_sound();
6867 snd_stop(Radar_static_looping);
6868 Radar_static_looping = -1;
6869 snd_stop(Target_static_looping);
6870 shipfx_stop_engine_wash_sound();
6871 Target_static_looping = -1;
6874 //////////////////////////////////////////////////////////////////////////
6876 // Code for supporting an animating mouse pointer
6879 //////////////////////////////////////////////////////////////////////////
6881 typedef struct animating_obj
6890 static animating_obj Animating_mouse;
6892 // ----------------------------------------------------------------------------
6893 // init_animating_pointer()
6895 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6896 // gets properly initialized
6898 void init_animating_pointer()
6900 Animating_mouse.first_frame = -1;
6901 Animating_mouse.num_frames = 0;
6902 Animating_mouse.current_frame = -1;
6903 Animating_mouse.time = 0.0f;
6904 Animating_mouse.elapsed_time = 0.0f;
6907 // ----------------------------------------------------------------------------
6908 // load_animating_pointer()
6910 // Called at game init to load in the frames for the animating mouse pointer
6912 // input: filename => filename of animation file that holds the animation
6914 void load_animating_pointer(const char *filename, int dx, int dy)
6919 init_animating_pointer();
6921 am = &Animating_mouse;
6922 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
6923 if ( am->first_frame == -1 )
6924 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
6925 am->current_frame = 0;
6926 am->time = am->num_frames / i2fl(fps);
6929 // ----------------------------------------------------------------------------
6930 // unload_animating_pointer()
6932 // Called at game shutdown to free the memory used to store the animation frames
6934 void unload_animating_pointer()
6939 am = &Animating_mouse;
6940 for ( i = 0; i < am->num_frames; i++ ) {
6941 SDL_assert( (am->first_frame+i) >= 0 );
6942 bm_release(am->first_frame + i);
6945 am->first_frame = -1;
6947 am->current_frame = -1;
6950 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
6951 void game_render_mouse(float frametime)
6956 // if animating cursor exists, play the next frame
6957 am = &Animating_mouse;
6958 if ( am->first_frame != -1 ) {
6959 mouse_get_pos(&mx, &my);
6960 am->elapsed_time += frametime;
6961 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
6962 if ( am->current_frame >= am->num_frames ) {
6963 am->current_frame = 0;
6964 am->elapsed_time = 0.0f;
6966 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
6970 // ----------------------------------------------------------------------------
6971 // game_maybe_draw_mouse()
6973 // determines whether to draw the mouse pointer at all, and what frame of
6974 // animation to use if the mouse is animating
6976 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
6978 // input: frametime => elapsed frame time in seconds since last call
6980 void game_maybe_draw_mouse(float frametime)
6984 game_state = gameseq_get_state();
6986 switch ( game_state ) {
6987 case GS_STATE_GAME_PAUSED:
6988 // case GS_STATE_MULTI_PAUSED:
6989 case GS_STATE_GAME_PLAY:
6990 case GS_STATE_DEATH_DIED:
6991 case GS_STATE_DEATH_BLEW_UP:
6992 if ( popup_active() || popupdead_is_active() ) {
7004 if ( !Mouse_hidden )
7005 game_render_mouse(frametime);
7009 void game_do_training_checks()
7013 waypoint_list *wplp;
7015 if (Training_context & TRAINING_CONTEXT_SPEED) {
7016 s = (int) Player_obj->phys_info.fspeed;
7017 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7018 if (!Training_context_speed_set) {
7019 Training_context_speed_set = 1;
7020 Training_context_speed_timestamp = timestamp();
7024 Training_context_speed_set = 0;
7027 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7028 wplp = &Waypoint_lists[Training_context_path];
7029 if (wplp->count > Training_context_goal_waypoint) {
7030 i = Training_context_goal_waypoint;
7032 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7033 if (d <= Training_context_distance) {
7034 Training_context_at_waypoint = i;
7035 if (Training_context_goal_waypoint == i) {
7036 Training_context_goal_waypoint++;
7037 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7044 if (i == wplp->count)
7047 } while (i != Training_context_goal_waypoint);
7051 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7052 Players_target = Player_ai->target_objnum;
7053 Players_targeted_subsys = Player_ai->targeted_subsys;
7054 Players_target_timestamp = timestamp();
7058 /////////// Following is for event debug view screen
7062 #define EVENT_DEBUG_MAX 5000
7063 #define EVENT_DEBUG_EVENT 0x8000
7065 int Event_debug_index[EVENT_DEBUG_MAX];
7068 void game_add_event_debug_index(int n, int indent)
7070 if (ED_count < EVENT_DEBUG_MAX)
7071 Event_debug_index[ED_count++] = n | (indent << 16);
7074 void game_add_event_debug_sexp(int n, int indent)
7079 if (Sexp_nodes[n].first >= 0) {
7080 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7081 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7085 game_add_event_debug_index(n, indent);
7086 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7087 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7089 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7092 void game_event_debug_init()
7097 for (e=0; e<Num_mission_events; e++) {
7098 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7099 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7103 void game_show_event_debug(float frametime)
7107 int font_height, font_width;
7109 static int scroll_offset = 0;
7111 k = game_check_key();
7117 if (scroll_offset < 0)
7127 scroll_offset -= 20;
7128 if (scroll_offset < 0)
7133 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7137 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7143 gr_set_color_fast(&Color_bright);
7145 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7147 gr_set_color_fast(&Color_normal);
7149 gr_get_string_size(&font_width, &font_height, NOX("test"));
7150 y_max = gr_screen.max_h - font_height - 5;
7154 while (k < ED_count) {
7155 if (y_index > y_max)
7158 z = Event_debug_index[k];
7159 if (z & EVENT_DEBUG_EVENT) {
7161 SDL_snprintf(buf, sizeof(buf), NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7162 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7163 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7164 Mission_events[z].repeat_count, Mission_events[z].interval);
7172 SDL_strlcat(buf, Sexp_nodes[z & 0x7fff].text, sizeof(buf));
7173 switch (Sexp_nodes[z & 0x7fff].value) {
7175 SDL_strlcat(buf, NOX(" (True)"), sizeof(buf));
7179 SDL_strlcat(buf, NOX(" (False)"), sizeof(buf));
7182 case SEXP_KNOWN_TRUE:
7183 SDL_strlcat(buf, NOX(" (Always true)"), sizeof(buf));
7186 case SEXP_KNOWN_FALSE:
7187 SDL_strlcat(buf, NOX(" (Always false)"), sizeof(buf));
7190 case SEXP_CANT_EVAL:
7191 SDL_strlcat(buf, NOX(" (Can't eval)"), sizeof(buf));
7195 case SEXP_NAN_FOREVER:
7196 SDL_strlcat(buf, NOX(" (Not a number)"), sizeof(buf));
7201 gr_printf(10, y_index, buf);
7202 y_index += font_height;
7215 int Tmap_num_too_big = 0;
7216 int Num_models_needing_splitting = 0;
7218 void Time_model( int modelnum )
7220 // mprintf(( "Timing ship '%s'\n", si->name ));
7222 vector eye_pos, model_pos;
7223 matrix eye_orient, model_orient;
7225 polymodel *pm = model_get( modelnum );
7227 int l = strlen(pm->filename);
7229 if ( (l == '/') || (l=='\\') || (l==':')) {
7235 char *pof_file = &pm->filename[l];
7237 int model_needs_splitting = 0;
7239 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7241 for (i=0; i<pm->n_textures; i++ ) {
7242 char filename[1024];
7245 int bmp_num = pm->original_textures[i];
7246 if ( bmp_num > -1 ) {
7247 bm_get_palette(pm->original_textures[i], pal, filename, sizeof(filename) );
7249 bm_get_info( pm->original_textures[i],&w, &h );
7252 if ( (w > 512) || (h > 512) ) {
7253 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7255 model_needs_splitting++;
7258 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7262 if ( model_needs_splitting ) {
7263 Num_models_needing_splitting++;
7265 eye_orient = model_orient = vmd_identity_matrix;
7266 eye_pos = model_pos = vmd_zero_vector;
7268 eye_pos.xyz.z = -pm->rad*2.0f;
7270 vector eye_to_model;
7272 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7273 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7275 fix t1 = timer_get_fixed_seconds();
7278 ta.p = ta.b = ta.h = 0.0f;
7281 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7283 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7285 modelstats_num_polys = modelstats_num_verts = 0;
7287 while( ta.h < PI2 ) {
7290 vm_angles_2_matrix(&m1, &ta );
7291 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7298 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7300 model_clear_instance( modelnum );
7301 model_set_detail_level(0); // use highest detail level
7302 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7310 int k = key_inkey();
7311 if ( k == SDLK_ESCAPE ) {
7316 fix t2 = timer_get_fixed_seconds();
7318 if (framecount < 1) {
7322 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7323 //bitmaps_used_this_frame /= framecount;
7325 modelstats_num_polys /= framecount;
7326 modelstats_num_verts /= framecount;
7328 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7329 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 );
7331 // 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 );
7337 int Time_models = 0;
7338 DCF_BOOL( time_models, Time_models );
7340 void Do_model_timings_test()
7344 if ( !Time_models ) return;
7346 mprintf(( "Timing models!\n" ));
7350 ubyte model_used[MAX_POLYGON_MODELS];
7351 int model_id[MAX_POLYGON_MODELS];
7352 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7357 for (i=0; i<Num_ship_types; i++ ) {
7358 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7360 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7361 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7364 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7365 if ( !Texture_fp ) return;
7367 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7368 if ( !Time_fp ) return;
7370 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7371 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7373 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7374 if ( model_used[i] ) {
7375 Time_model( model_id[i] );
7379 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7380 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7389 // Call this function when you want to inform the player that a feature is not
7390 // enabled in the DEMO version of FreSpace
7391 void game_feature_not_in_demo_popup()
7393 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7396 // format the specified time (fixed point) into a nice string
7397 void game_format_time(fix m_time, char *time_str, const int time_str_len)
7400 int hours,minutes,seconds;
7402 mtime = f2fl(m_time);
7404 // get the hours, minutes and seconds
7405 hours = (int)(mtime / 3600.0f);
7407 mtime -= (3600.0f * (float)hours);
7409 seconds = (int)mtime%60;
7410 minutes = (int)mtime/60;
7413 SDL_snprintf(time_str, time_str_len, "%d:%02d:%02d", hours, minutes, seconds);
7415 SDL_snprintf(time_str, time_str_len, "%d:%02d", minutes, seconds);
7419 // Stuff version string in *str.
7420 void get_version_string(char *str, const int str_len)
7423 if ( FS_VERSION_BUILD == 0 ) {
7424 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7426 SDL_snprintf(str, str_len, "v%d.%02d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7429 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7430 SDL_strlcat(str, " D", str_len);
7431 #elif defined (OEM_BUILD)
7432 SDL_strlcat(str, " (OEM)", str_len);
7438 char myname[_MAX_PATH];
7439 int namelen, major, minor, build, waste;
7440 unsigned int buf_size;
7446 // Find my EXE file name
7447 hMod = GetModuleHandle(NULL);
7448 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7450 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7451 infop = (char *)malloc(version_size);
7452 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7454 // get the product version
7455 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7456 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7458 sprintf(str,"Dv%d.%02d",major, minor);
7460 sprintf(str,"v%d.%02d",major, minor);
7465 void get_version_string_short(char *str, const int str_len)
7467 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7470 // ----------------------------------------------------------------
7472 // OEM UPSELL SCREENS BEGIN
7474 // ----------------------------------------------------------------
7475 #if defined(OEM_BUILD)
7477 #define NUM_OEM_UPSELL_SCREENS 3
7478 #define OEM_UPSELL_SCREEN_DELAY 10000
7480 static int Oem_upsell_bitmaps_loaded = 0;
7481 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7482 static int Oem_upsell_screen_number = 0;
7483 static int Oem_upsell_show_next_bitmap_time;
7486 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7499 static int Oem_normal_cursor = -1;
7500 static int Oem_web_cursor = -1;
7501 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7502 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7504 void oem_upsell_next_screen()
7506 Oem_upsell_screen_number++;
7507 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7508 // extra long delay, mouse shown on last upsell
7509 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7513 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7517 void oem_upsell_load_bitmaps()
7521 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7522 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7526 void oem_upsell_unload_bitmaps()
7530 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7531 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7532 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7537 Oem_upsell_bitmaps_loaded = 0;
7540 // clickable hotspot on 3rd OEM upsell screen
7541 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7543 28, 350, 287, 96 // x, y, w, h
7546 45, 561, 460, 152 // x, y, w, h
7550 void oem_upsell_show_screens()
7552 int current_time, k;
7555 if ( !Oem_upsell_bitmaps_loaded ) {
7556 oem_upsell_load_bitmaps();
7557 Oem_upsell_bitmaps_loaded = 1;
7560 // may use upsell screens more than once
7561 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7562 Oem_upsell_screen_number = 0;
7568 int nframes; // used to pass, not really needed (should be 1)
7569 Oem_normal_cursor = gr_get_cursor_bitmap();
7570 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7571 SDL_assert(Oem_web_cursor >= 0);
7572 if (Oem_web_cursor < 0) {
7573 Oem_web_cursor = Oem_normal_cursor;
7578 //oem_reset_trailer_timer();
7580 current_time = timer_get_milliseconds();
7585 // advance screen on keypress or timeout
7586 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7587 oem_upsell_next_screen();
7590 // check if we are done
7591 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7592 Oem_upsell_screen_number--;
7595 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7600 // show me the upsell
7601 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7602 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7606 // if this is the 3rd upsell, make it clickable, d00d
7607 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7609 int button_state = mouse_get_pos(&mx, &my);
7610 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])
7611 && (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]) )
7614 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7617 if (button_state & MOUSE_LEFT_BUTTON) {
7619 multi_pxo_url(OEM_UPSELL_URL);
7623 // switch cursor back to normal one
7624 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7629 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7639 oem_upsell_unload_bitmaps();
7641 // switch cursor back to normal one
7642 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7646 #endif // defined(OEM_BUILD)
7647 // ----------------------------------------------------------------
7649 // OEM UPSELL SCREENS END
7651 // ----------------------------------------------------------------
7655 // ----------------------------------------------------------------
7657 // DEMO UPSELL SCREENS BEGIN
7659 // ----------------------------------------------------------------
7661 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7664 #define NUM_DEMO_UPSELL_SCREENS 2
7666 #define NUM_DEMO_UPSELL_SCREENS 4
7668 #define DEMO_UPSELL_SCREEN_DELAY 3000
7670 static int Demo_upsell_bitmaps_loaded = 0;
7671 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7672 static int Demo_upsell_screen_number = 0;
7673 static int Demo_upsell_show_next_bitmap_time;
7676 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7702 void demo_upsell_next_screen()
7704 Demo_upsell_screen_number++;
7705 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7706 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7708 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7712 void demo_upsell_load_bitmaps()
7716 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7717 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7721 void demo_upsell_unload_bitmaps()
7725 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7726 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7727 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7732 Demo_upsell_bitmaps_loaded = 0;
7735 void demo_upsell_show_screens()
7737 int current_time, k;
7740 if ( !Demo_upsell_bitmaps_loaded ) {
7741 demo_upsell_load_bitmaps();
7742 Demo_upsell_bitmaps_loaded = 1;
7745 // may use upsell screens more than once
7746 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7747 Demo_upsell_screen_number = 0;
7754 demo_reset_trailer_timer();
7756 current_time = timer_get_milliseconds();
7763 // don't time out, wait for keypress
7765 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7766 demo_upsell_next_screen();
7771 demo_upsell_next_screen();
7774 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7775 Demo_upsell_screen_number--;
7778 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7783 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7784 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7789 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7799 demo_upsell_unload_bitmaps();
7804 // ----------------------------------------------------------------
7806 // DEMO UPSELL SCREENS END
7808 // ----------------------------------------------------------------
7811 // ----------------------------------------------------------------
7813 // Subspace Ambient Sound START
7815 // ----------------------------------------------------------------
7817 static int Subspace_ambient_left_channel = -1;
7818 static int Subspace_ambient_right_channel = -1;
7821 void game_start_subspace_ambient_sound()
7823 if ( Subspace_ambient_left_channel < 0 ) {
7824 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7827 if ( Subspace_ambient_right_channel < 0 ) {
7828 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7832 void game_stop_subspace_ambient_sound()
7834 if ( Subspace_ambient_left_channel >= 0 ) {
7835 snd_stop(Subspace_ambient_left_channel);
7836 Subspace_ambient_left_channel = -1;
7839 if ( Subspace_ambient_right_channel >= 0 ) {
7840 snd_stop(Subspace_ambient_right_channel);
7841 Subspace_ambient_right_channel = -1;
7845 // ----------------------------------------------------------------
7847 // Subspace Ambient Sound END
7849 // ----------------------------------------------------------------
7851 // ----------------------------------------------------------------
7853 // Language Autodetection stuff
7856 // this layout order must match Lcl_languages in localize.cpp in order for the
7857 // correct language to be detected
7858 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
7860 1366105450, // English
7862 589986744, // English
7864 -1132430286, // German
7866 -1131728960, // Polish
7869 // default setting is "-1" to use config file with English as fall back
7870 // DO NOT change the default setting here or something uncouth might happen
7871 // in the localization code
7877 // try and open the file to verify
7878 CFILE *detect = cfopen("font01.vf", "rb");
7880 // will use default setting if something went wrong
7885 // get the long checksum of the file
7887 cfseek(detect, 0, SEEK_SET);
7888 cf_chksum_long(detect, &file_checksum);
7892 // now compare the checksum/filesize against known #'s
7893 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
7894 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
7899 // notify if a match was not found, include detected checksum
7900 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
7901 printf("Using default language...\n\n");
7907 // End Auto Lang stuff
7909 // ----------------------------------------------------------------
7911 // ----------------------------------------------------------------
7912 // SHIPS TBL VERIFICATION STUFF
7915 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
7916 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
7917 #define NUM_SHIPS_TBL_CHECKSUMS 3
7919 #define NUM_SHIPS_TBL_CHECKSUMS 1
7923 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7924 1696074201, // FS2 demo
7927 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7928 1603375034, // FS1 DEMO
7931 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7932 -129679197, // FS1 Full 1.06 (US)
7933 7762567, // FS1 SilentThreat
7934 1555372475 // FS1 Full 1.06 (German)
7938 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7939 -463907578, // US - beta 1
7940 1696074201, // FS2 demo
7943 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7944 // -1022810006, // 1.0 FULL
7945 -1254285366 // 1.2 FULL (German)
7949 void verify_ships_tbl()
7953 Game_ships_tbl_valid = 1;
7959 // detect if the packfile exists
7960 CFILE *detect = cfopen("ships.tbl", "rb");
7961 Game_ships_tbl_valid = 0;
7965 Game_ships_tbl_valid = 0;
7969 // get the long checksum of the file
7971 cfseek(detect, 0, SEEK_SET);
7972 cf_chksum_long(detect, &file_checksum);
7976 // now compare the checksum/filesize against known #'s
7977 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
7978 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
7979 Game_ships_tbl_valid = 1;
7986 DCF(shipspew, "display the checksum for the current ships.tbl")
7989 CFILE *detect = cfopen("ships.tbl", "rb");
7990 // get the long checksum of the file
7992 cfseek(detect, 0, SEEK_SET);
7993 cf_chksum_long(detect, &file_checksum);
7996 dc_printf("%d", file_checksum);
7999 // ----------------------------------------------------------------
8000 // WEAPONS TBL VERIFICATION STUFF
8003 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8004 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8005 #define NUM_WEAPONS_TBL_CHECKSUMS 3
8007 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8011 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8012 -266420030, // demo 1
8015 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8016 -1246928725, // FS1 DEMO
8019 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8020 -834598107, // FS1 1.06 Full (US)
8021 -1652231417, // FS1 SilentThreat
8022 720209793 // FS1 1.06 Full (German)
8026 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8027 141718090, // US - beta 1
8028 -266420030, // demo 1
8031 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8032 // 399297860, // 1.0 FULL
8033 -553984927 // 1.2 FULL (german)
8037 void verify_weapons_tbl()
8041 Game_weapons_tbl_valid = 1;
8047 // detect if the packfile exists
8048 CFILE *detect = cfopen("weapons.tbl", "rb");
8049 Game_weapons_tbl_valid = 0;
8053 Game_weapons_tbl_valid = 0;
8057 // get the long checksum of the file
8059 cfseek(detect, 0, SEEK_SET);
8060 cf_chksum_long(detect, &file_checksum);
8064 // now compare the checksum/filesize against known #'s
8065 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8066 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8067 Game_weapons_tbl_valid = 1;
8074 DCF(wepspew, "display the checksum for the current weapons.tbl")
8077 CFILE *detect = cfopen("weapons.tbl", "rb");
8078 // get the long checksum of the file
8080 cfseek(detect, 0, SEEK_SET);
8081 cf_chksum_long(detect, &file_checksum);
8084 dc_printf("%d", file_checksum);
8087 // if the game is running using hacked data
8088 int game_hacked_data()
8091 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8099 void display_title_screen()
8101 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
8102 ///int title_bitmap;
8105 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8106 if (title_bitmap == -1) {
8111 gr_set_bitmap(title_bitmap);
8119 bm_unload(title_bitmap);
8120 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
8123 // return true if the game is running with "low memory", which is less than 48MB
8124 bool game_using_low_mem()
8126 if (Use_low_mem == 0) {