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.35 2004/06/11 00:53:02 tigital
19 * OSX: .app name, casts for gcc
21 * Revision 1.34 2003/08/09 03:18:03 taylor
22 * fix tips popup not having any tips
24 * Revision 1.33 2003/08/03 15:57:00 taylor
25 * simpler mouse usage; default ini settings in os_init(); cleanup
27 * Revision 1.32 2003/06/19 11:51:41 taylor
28 * adjustments to memory leak fixes
30 * Revision 1.31 2003/06/11 18:30:32 taylor
33 * Revision 1.30 2003/06/03 04:00:39 taylor
34 * Polish language support (Janusz Dziemidowicz)
36 * Revision 1.29 2003/05/25 02:30:42 taylor
39 * Revision 1.28 2003/05/18 03:55:30 taylor
40 * automatic language selection support
42 * Revision 1.27 2003/03/03 04:54:44 theoddone33
43 * Commit Taylor's ShowFPS fix
45 * Revision 1.26 2003/02/20 17:41:07 theoddone33
46 * Userdir patch from Taylor Richards
48 * Revision 1.25 2003/01/30 19:54:10 relnev
49 * ini config option for the frames per second counter (Taylor Richards)
51 * Revision 1.24 2002/08/31 01:39:13 theoddone33
52 * Speed up the renderer a tad
54 * Revision 1.23 2002/08/04 02:31:00 relnev
55 * make numlock not overlap with pause
57 * Revision 1.22 2002/08/02 23:07:03 relnev
58 * don't access the mouse in standalone mode
60 * Revision 1.21 2002/07/28 05:05:08 relnev
61 * removed some old stuff
63 * Revision 1.20 2002/07/24 00:20:41 relnev
66 * Revision 1.19 2002/06/17 06:33:08 relnev
67 * ryan's struct patch for gcc 2.95
69 * Revision 1.18 2002/06/16 04:46:33 relnev
70 * set up correct checksums for demo
72 * Revision 1.17 2002/06/09 04:41:17 relnev
73 * added copyright header
75 * Revision 1.16 2002/06/09 03:16:04 relnev
78 * removed unneeded asm, old sdl 2d setup.
80 * fixed crash caused by opengl_get_region.
82 * Revision 1.15 2002/06/05 08:05:28 relnev
83 * stub/warning removal.
85 * reworked the sound code.
87 * Revision 1.14 2002/06/05 04:03:32 relnev
88 * finished cfilesystem.
90 * removed some old code.
92 * fixed mouse save off-by-one.
96 * Revision 1.13 2002/06/02 04:26:34 relnev
99 * Revision 1.12 2002/06/02 00:31:35 relnev
100 * implemented osregistry
102 * Revision 1.11 2002/06/01 09:00:34 relnev
103 * silly debug memmanager
105 * Revision 1.10 2002/06/01 07:12:32 relnev
106 * a few NDEBUG updates.
108 * removed a few warnings.
110 * Revision 1.9 2002/05/31 03:05:59 relnev
113 * Revision 1.8 2002/05/29 02:52:32 theoddone33
114 * Enable OpenGL renderer
116 * Revision 1.7 2002/05/28 08:52:03 relnev
117 * implemented two assembly stubs.
119 * cleaned up a few warnings.
121 * added a little demo hackery to make it progress a little farther.
123 * Revision 1.6 2002/05/28 06:28:20 theoddone33
124 * Filesystem mods, actually reads some data files now
126 * Revision 1.5 2002/05/28 04:07:28 theoddone33
127 * New graphics stubbing arrangement
129 * Revision 1.4 2002/05/27 22:46:52 theoddone33
130 * Remove more undefined symbols
132 * Revision 1.3 2002/05/26 23:31:18 relnev
133 * added a few files that needed to be compiled
135 * freespace.cpp: now compiles
137 * Revision 1.2 2002/05/07 03:16:44 theoddone33
138 * The Great Newline Fix
140 * Revision 1.1.1.1 2002/05/03 03:28:09 root
144 * 201 6/16/00 3:15p Jefff
145 * sim of the year dvd version changes, a few german soty localization
148 * 200 11/03/99 11:06a Jefff
151 * 199 10/26/99 5:07p Jamest
152 * fixed jeffs dumb debug code
154 * 198 10/25/99 5:53p Jefff
155 * call control_config_common_init() on startup
157 * 197 10/14/99 10:18a Daveb
158 * Fixed incorrect CD checking problem on standalone server.
160 * 196 10/13/99 9:22a Daveb
161 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
162 * related to movies. Fixed launcher spawning from PXO screen.
164 * 195 10/06/99 11:05a Jefff
165 * new oem upsell 3 hotspot coords
167 * 194 10/06/99 10:31a Jefff
170 * 193 10/01/99 9:10a Daveb
173 * 192 9/15/99 4:57a Dave
174 * Updated ships.tbl checksum
176 * 191 9/15/99 3:58a Dave
177 * Removed framerate warning at all times.
179 * 190 9/15/99 3:16a Dave
180 * Remove mt-011.fs2 from the builtin mission list.
182 * 189 9/15/99 1:45a Dave
183 * Don't init joystick on standalone. Fixed campaign mode on standalone.
184 * Fixed no-score-report problem in TvT
186 * 188 9/14/99 6:08a Dave
187 * Updated (final) single, multi, and campaign list.
189 * 187 9/14/99 3:26a Dave
190 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
191 * respawn-too-early problem. Made a few crash points safe.
193 * 186 9/13/99 4:52p Dave
196 * 185 9/12/99 8:09p Dave
197 * Fixed problem where skip-training button would cause mission messages
198 * not to get paged out for the current mission.
200 * 184 9/10/99 11:53a Dave
201 * Shutdown graphics before sound to eliminate apparent lockups when
202 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
204 * 183 9/09/99 11:40p Dave
205 * Handle an Assert() in beam code. Added supernova sounds. Play the right
206 * 2 end movies properly, based upon what the player did in the mission.
208 * 182 9/08/99 10:29p Dave
209 * Make beam sound pausing and unpausing much safer.
211 * 181 9/08/99 10:01p Dave
212 * Make sure game won't run in a drive's root directory. Make sure
213 * standalone routes suqad war messages properly to the host.
215 * 180 9/08/99 3:22p Dave
216 * Updated builtin mission list.
218 * 179 9/08/99 12:01p Jefff
219 * fixed Game_builtin_mission_list typo on Training-2.fs2
221 * 178 9/08/99 9:48a Andsager
222 * Add force feedback for engine wash.
224 * 177 9/07/99 4:01p Dave
225 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
226 * does everything properly (setting up address when binding). Remove
227 * black rectangle background from UI_INPUTBOX.
229 * 176 9/13/99 2:40a Dave
230 * Comment in full 80 minute CD check for RELEASE_REAL builds.
232 * 175 9/06/99 6:38p Dave
233 * Improved CD detection code.
235 * 174 9/06/99 1:30a Dave
236 * Intermediate checkin. Started on enforcing CD-in-drive to play the
239 * 173 9/06/99 1:16a Dave
240 * Make sure the user sees the intro movie.
242 * 172 9/04/99 8:00p Dave
243 * Fixed up 1024 and 32 bit movie support.
245 * 171 9/03/99 1:32a Dave
246 * CD checking by act. Added support to play 2 cutscenes in a row
247 * seamlessly. Fixed super low level cfile bug related to files in the
248 * root directory of a CD. Added cheat code to set campaign mission # in
251 * 170 9/01/99 10:49p Dave
252 * Added nice SquadWar checkbox to the client join wait screen.
254 * 169 9/01/99 10:14a Dave
257 * 168 8/29/99 4:51p Dave
258 * Fixed damaged checkin.
260 * 167 8/29/99 4:18p Andsager
261 * New "burst" limit for friendly damage. Also credit more damage done
262 * against large friendly ships.
264 * 166 8/27/99 6:38p Alanl
265 * crush the blasted repeating messages bug
267 * 164 8/26/99 9:09p Dave
268 * Force framerate check in everything but a RELEASE_REAL build.
270 * 163 8/26/99 9:45a Dave
271 * First pass at easter eggs and cheats.
273 * 162 8/24/99 8:55p Dave
274 * Make sure nondimming pixels work properly in tech menu.
276 * 161 8/24/99 1:49a Dave
277 * Fixed client-side afterburner stuttering. Added checkbox for no version
278 * checking on PXO join. Made button info passing more friendly between
281 * 160 8/22/99 5:53p Dave
282 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
283 * instead of ship designations for multiplayer players.
285 * 159 8/22/99 1:19p Dave
286 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
287 * which d3d cards are detected.
289 * 158 8/20/99 2:09p Dave
290 * PXO banner cycling.
292 * 157 8/19/99 10:59a Dave
293 * Packet loss detection.
295 * 156 8/19/99 10:12a Alanl
296 * preload mission-specific messages on machines greater than 48MB
298 * 155 8/16/99 4:04p Dave
299 * Big honking checkin.
301 * 154 8/11/99 5:54p Dave
302 * Fixed collision problem. Fixed standalone ghost problem.
304 * 153 8/10/99 7:59p Jefff
307 * 152 8/10/99 6:54p Dave
308 * Mad optimizations. Added paging to the nebula effect.
310 * 151 8/10/99 3:44p Jefff
311 * loads Intelligence information on startup
313 * 150 8/09/99 3:47p Dave
314 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
315 * non-nebula missions.
317 * 149 8/09/99 2:21p Andsager
318 * Fix patching from multiplayer direct to launcher update tab.
320 * 148 8/09/99 10:36a Dave
321 * Version info for game.
323 * 147 8/06/99 9:46p Dave
324 * Hopefully final changes for the demo.
326 * 146 8/06/99 3:34p Andsager
327 * Make title version info "(D)" -> "D" show up nicely
329 * 145 8/06/99 2:59p Adamp
330 * Fixed NT launcher/update problem.
332 * 144 8/06/99 1:52p Dave
333 * Bumped up MAX_BITMAPS for the demo.
335 * 143 8/06/99 12:17p Andsager
336 * Demo: down to just 1 demo dog
338 * 142 8/05/99 9:39p Dave
339 * Yet another new checksum.
341 * 141 8/05/99 6:19p Dave
342 * New demo checksums.
344 * 140 8/05/99 5:31p Andsager
345 * Up demo version 1.01
347 * 139 8/05/99 4:22p Andsager
348 * No time limit on upsell screens. Reverse order of display of upsell
351 * 138 8/05/99 4:17p Dave
352 * Tweaks to client interpolation.
354 * 137 8/05/99 3:52p Danw
356 * 136 8/05/99 3:01p Danw
358 * 135 8/05/99 2:43a Anoop
359 * removed duplicate definition.
361 * 134 8/05/99 2:13a Dave
364 * 133 8/05/99 2:05a Dave
367 * 132 8/05/99 1:22a Andsager
370 * 131 8/04/99 9:51p Andsager
371 * Add title screen to demo
373 * 130 8/04/99 6:47p Jefff
374 * fixed link error resulting from #ifdefs
376 * 129 8/04/99 6:26p Dave
377 * Updated ship tbl checksum.
379 * 128 8/04/99 5:40p Andsager
380 * Add multiple demo dogs
382 * 127 8/04/99 5:36p Andsager
383 * Show upsell screens at end of demo campaign before returning to main
386 * 126 8/04/99 11:42a Danw
387 * tone down EAX reverb
389 * 125 8/04/99 11:23a Dave
390 * Updated demo checksums.
392 * 124 8/03/99 11:02p Dave
393 * Maybe fixed sync problems in multiplayer.
395 * 123 8/03/99 6:21p Jefff
398 * 122 8/03/99 3:44p Andsager
399 * Launch laucher if trying to run FS without first having configured
402 * 121 8/03/99 12:45p Dave
405 * 120 8/02/99 9:13p Dave
408 * 119 7/30/99 10:31p Dave
409 * Added comm menu to the configurable hud files.
411 * 118 7/30/99 5:17p Andsager
412 * first fs2demo checksums
414 * 117 7/29/99 3:09p Anoop
416 * 116 7/29/99 12:05a Dave
417 * Nebula speed optimizations.
419 * 115 7/27/99 8:59a Andsager
420 * Make major, minor version consistent for all builds. Only show major
421 * and minor for launcher update window.
423 * 114 7/26/99 5:50p Dave
424 * Revised ingame join. Better? We'll see....
426 * 113 7/26/99 5:27p Andsager
427 * Add training mission as builtin to demo build
429 * 112 7/24/99 1:54p Dave
430 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
433 * 111 7/22/99 4:00p Dave
434 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
436 * 110 7/21/99 8:10p Dave
437 * First run of supernova effect.
439 * 109 7/20/99 1:49p Dave
440 * Peter Drake build. Fixed some release build warnings.
442 * 108 7/19/99 2:26p Andsager
443 * set demo multiplayer missions
445 * 107 7/18/99 5:19p Dave
446 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
448 * 106 7/16/99 1:50p Dave
449 * 8 bit aabitmaps. yay.
451 * 105 7/15/99 3:07p Dave
452 * 32 bit detection support. Mouse coord commandline.
454 * 104 7/15/99 2:13p Dave
455 * Added 32 bit detection.
457 * 103 7/15/99 9:20a Andsager
458 * FS2_DEMO initial checkin
460 * 102 7/14/99 11:02a Dave
461 * Skill level default back to easy. Blech.
463 * 101 7/09/99 5:54p Dave
464 * Seperated cruiser types into individual types. Added tons of new
465 * briefing icons. Campaign screen.
467 * 100 7/08/99 4:43p Andsager
468 * New check for sparky_hi and print if not found.
470 * 99 7/08/99 10:53a Dave
471 * New multiplayer interpolation scheme. Not 100% done yet, but still
472 * better than the old way.
474 * 98 7/06/99 4:24p Dave
475 * Mid-level checkin. Starting on some potentially cool multiplayer
478 * 97 7/06/99 3:35p Andsager
479 * Allow movie to play before red alert mission.
481 * 96 7/03/99 5:50p Dave
482 * Make rotated bitmaps draw properly in padlock views.
484 * 95 7/02/99 9:55p Dave
485 * Player engine wash sound.
487 * 94 7/02/99 4:30p Dave
488 * Much more sophisticated lightning support.
490 * 93 6/29/99 7:52p Dave
491 * Put in exception handling in FS2.
493 * 92 6/22/99 9:37p Dave
494 * Put in pof spewing.
496 * 91 6/16/99 4:06p Dave
497 * New pilot info popup. Added new draw-bitmap-as-poly function.
499 * 90 6/15/99 1:56p Andsager
500 * For release builds, allow start up in high res only with
503 * 89 6/15/99 9:34a Dave
504 * Fixed key checking in single threaded version of the stamp notification
507 * 88 6/09/99 2:55p Andsager
508 * Allow multiple asteroid subtypes (of large, medium, small) and follow
511 * 87 6/08/99 1:14a Dave
512 * Multi colored hud test.
514 * 86 6/04/99 9:52a Dave
515 * Fixed some rendering problems.
517 * 85 6/03/99 10:15p Dave
518 * Put in temporary main hall screen.
520 * 84 6/02/99 6:18p Dave
521 * Fixed TNT lockup problems! Wheeeee!
523 * 83 6/01/99 3:52p Dave
524 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
525 * dead popup, pxo find player popup, pxo private room popup.
527 * 82 5/26/99 1:28p Jasenw
528 * changed coords for loading ani
530 * 81 5/26/99 11:46a Dave
531 * Added ship-blasting lighting and made the randomization of lighting
532 * much more customizable.
534 * 80 5/24/99 5:45p Dave
535 * Added detail levels to the nebula, with a decent speedup. Split nebula
536 * lightning into its own section.
554 #include "systemvars.h"
559 #include "starfield.h"
560 #include "lighting.h"
565 #include "fireballs.h"
569 #include "floating.h"
570 #include "gamesequence.h"
572 #include "optionsmenu.h"
573 #include "playermenu.h"
574 #include "trainingmenu.h"
575 #include "techmenu.h"
578 #include "hudmessage.h"
580 #include "missiongoals.h"
581 #include "missionparse.h"
586 #include "multiutil.h"
587 #include "multimsgs.h"
591 #include "freespace.h"
592 #include "managepilot.h"
594 #include "contexthelp.h"
597 #include "missionbrief.h"
598 #include "missiondebrief.h"
600 #include "missionshipchoice.h"
602 #include "hudconfig.h"
603 #include "controlsconfig.h"
604 #include "missionmessage.h"
605 #include "missiontraining.h"
607 #include "hudtarget.h"
609 #include "eventmusic.h"
610 #include "animplay.h"
611 #include "missionweaponchoice.h"
612 #include "missionlog.h"
613 #include "audiostr.h"
615 #include "missioncampaign.h"
617 #include "missionhotkey.h"
618 #include "objectsnd.h"
619 #include "cmeasure.h"
621 #include "linklist.h"
622 #include "shockwave.h"
623 #include "afterburner.h"
628 #include "stand_gui.h"
629 #include "pcxutils.h"
630 #include "hudtargetbox.h"
631 #include "multi_xfer.h"
632 #include "hudescort.h"
633 #include "multiutil.h"
636 #include "multiteamselect.h"
639 #include "readyroom.h"
640 #include "mainhallmenu.h"
641 #include "multilag.h"
643 #include "particle.h"
645 #include "multi_ingame.h"
646 #include "snazzyui.h"
647 #include "asteroid.h"
648 #include "popupdead.h"
649 #include "multi_voice.h"
650 #include "missioncmdbrief.h"
651 #include "redalert.h"
652 #include "gameplayhelp.h"
653 #include "multilag.h"
654 #include "staticrand.h"
655 #include "multi_pmsg.h"
656 #include "levelpaging.h"
657 #include "observer.h"
658 #include "multi_pause.h"
659 #include "multi_endgame.h"
660 #include "cutscenes.h"
661 #include "multi_respawn.h"
663 #include "multi_obj.h"
664 #include "multi_log.h"
666 #include "localize.h"
667 #include "osregistry.h"
668 #include "barracks.h"
669 #include "missionpause.h"
671 #include "alphacolors.h"
672 #include "objcollide.h"
675 #include "neblightning.h"
676 #include "shipcontrails.h"
679 #include "multi_dogfight.h"
680 #include "multi_rate.h"
681 #include "muzzleflash.h"
685 #include "mainhalltemp.h"
686 #include "exceptionhandler.h"
690 #include "supernova.h"
691 #include "hudshield.h"
692 // #include "names.h"
694 #include "missionloopbrief.h"
698 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
704 // 1.00.04 5/26/98 MWA -- going final (12 pm)
705 // 1.00.03 5/26/98 MWA -- going final (3 am)
706 // 1.00.02 5/25/98 MWA -- going final
707 // 1.00.01 5/25/98 MWA -- going final
708 // 0.90 5/21/98 MWA -- getting ready for final.
709 // 0.10 4/9/98. Set by MK.
711 // Demo version: (obsolete since DEMO codebase split from tree)
712 // 0.03 4/10/98 AL. Interplay rev
713 // 0.02 4/8/98 MK. Increased when this system was modified.
714 // 0.01 4/7/98? AL. First release to Interplay QA.
717 // 1.00 5/28/98 AL. First release to Interplay QA.
719 void game_level_init(int seed = -1);
720 void game_post_level_init();
721 void game_do_frame();
722 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
723 void game_reset_time();
724 void game_show_framerate(); // draws framerate in lower right corner
726 int Game_no_clear = 0;
728 int Pofview_running = 0;
729 int Nebedit_running = 0;
731 typedef struct big_expl_flash {
732 float max_flash_intensity; // max intensity
733 float cur_flash_intensity; // cur intensity
734 int flash_start; // start time
737 #define FRAME_FILTER 16
739 #define DEFAULT_SKILL_LEVEL 1
740 int Game_skill_level = DEFAULT_SKILL_LEVEL;
742 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
743 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
746 #define EXE_FNAME ("fs2.exe")
747 #define LAUNCHER_FNAME ("freespace2.exe")
749 #define EXE_FNAME ("Freespace2demo.app")
750 #define LAUNCHER_FNAME ("Freespace2demo.app")
751 char app_path[] = "Freespace2demo.app/Contents/MacOS/Freespace2demo";
753 #define EXE_FNAME ("Freespace1demo.app")
754 #define LAUNCHER_FNAME ("Freespace1demo.app")
755 char app_path[] = "Freespace1demo.app/Contents/MacOS/Freespace1demo";
757 #define EXE_FNAME ("Freespace1.app")
758 #define LAUNCHER_FNAME ("Freespace1.app")
759 char app_path[] ="Freespace1.app/Contents/MacOS/Freespace1";
761 #define EXE_FNAME ("Freespace2.app")
762 #define LAUNCHER_FNAME ("Freespace2.app")
763 char app_path[] ="Freespace2.app/Contents/MacOS/Freespace2";
767 extern char full_path[1024];
770 // JAS: Code for warphole camera.
771 // Needs to be cleaned up.
772 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
773 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
774 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
775 matrix Camera_orient = IDENTITY_MATRIX;
776 float Camera_damping = 1.0f;
777 float Camera_time = 0.0f;
778 float Warpout_time = 0.0f;
779 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
780 int Warpout_sound = -1;
782 int Use_joy_mouse = 0;
783 int Use_palette_flash = 1;
785 int Use_fullscreen_at_startup = 0;
787 int Show_area_effect = 0;
788 object *Last_view_target = NULL;
790 int dogfight_blown = 0;
793 float frametimes[FRAME_FILTER];
794 float frametotal = 0.0f;
798 int Show_framerate = 0;
800 int Show_framerate = 1;
803 int Framerate_cap = 120;
806 int Show_target_debug_info = 0;
807 int Show_target_weapons = 0;
811 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
814 int Debug_octant = -1;
816 fix Game_time_compression = F1_0;
818 // if the ships.tbl the player has is valid
819 int Game_ships_tbl_valid = 0;
821 // if the weapons.tbl the player has is valid
822 int Game_weapons_tbl_valid = 0;
826 extern int Player_attacking_enabled;
830 int Pre_player_entry;
832 int Fred_running = 0;
833 char Game_current_mission_filename[MAX_FILENAME_LEN];
834 int game_single_step = 0;
835 int last_single_step=0;
837 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
838 extern int MSG_WINDOW_Y_START;
839 extern int MSG_WINDOW_HEIGHT;
841 int game_zbuffer = 1;
842 //static int Game_music_paused;
843 static int Game_paused;
847 #define EXPIRE_BAD_CHECKSUM 1
848 #define EXPIRE_BAD_TIME 2
850 extern void ssm_init();
851 extern void ssm_level_init();
852 extern void ssm_process();
854 // static variable to contain the time this version was built
855 // commented out for now until
856 // I figure out how to get the username into the file
857 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
859 // defines and variables used for dumping frame for making trailers.
861 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
862 int Debug_dump_trigger = 0;
863 int Debug_dump_frame_count;
864 int Debug_dump_frame_num = 0;
865 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
868 // amount of time to wait after the player has died before we display the death died popup
869 #define PLAYER_DIED_POPUP_WAIT 2500
870 int Player_died_popup_wait = -1;
871 int Player_multi_died_check = -1;
873 // builtin mission list stuff
875 int Game_builtin_mission_count = 6;
876 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
877 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
878 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
879 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
880 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
881 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 #elif defined(FS1_DEMO)
885 int Game_builtin_mission_count = 5;
886 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
887 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
888 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
889 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
890 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
891 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
893 #elif defined(PD_BUILD)
894 int Game_builtin_mission_count = 4;
895 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
896 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
897 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
898 { "sm1-01", (FSB_FROM_VOLITION), "" },
899 { "sm1-05", (FSB_FROM_VOLITION), "" },
901 #elif defined(MULTIPLAYER_BETA)
902 int Game_builtin_mission_count = 17;
903 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
905 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
918 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
919 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
920 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
921 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
923 #elif defined(OEM_BUILD)
924 int Game_builtin_mission_count = 17;
925 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
926 // oem version - act 1 only
927 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
930 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
931 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
932 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
933 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
934 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
935 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
936 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
937 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
938 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
939 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
940 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
941 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
942 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
943 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
944 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
945 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
947 #elif defined(MAKE_FS1)
948 int Game_builtin_mission_count = 125;
949 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
950 // single player campaign
951 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
954 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
955 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
956 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
957 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
958 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
959 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
960 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
961 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
962 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
963 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
966 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
967 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
968 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
969 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
970 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
971 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
972 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
973 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
974 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
975 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
978 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
979 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
980 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
981 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
982 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
983 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
984 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
985 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
986 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
989 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
990 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
991 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
994 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
995 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
996 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
997 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
998 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
1001 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1002 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1004 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1005 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1006 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1007 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1008 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1009 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1010 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1011 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1012 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1013 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1014 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1015 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1016 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1017 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1018 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1019 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1020 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1021 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1022 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1024 // SilentThreat missions
1025 // Main SilentThreat campaign
1026 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE), "" },
1028 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1029 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1030 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1031 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1032 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1033 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1034 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1035 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1036 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1037 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1038 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1039 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1041 // SilentThreat Part 1 - multi-coop
1042 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1044 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1045 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1046 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1048 // SilentThreat Part 2 - multi-coop
1049 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1051 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1052 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1053 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1055 // SilentThreat Part 3 - multi-coop
1056 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1058 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1059 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1060 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1062 // SilentThreat Part 4 - multi-coop
1063 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1065 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1066 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1067 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1069 // multiplayer missions
1070 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1071 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1072 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1073 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1074 // user supplied missions
1075 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1076 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1077 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1078 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1079 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1080 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1081 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1082 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1083 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1084 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1085 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1086 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1087 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1088 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1089 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1090 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1091 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1092 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1093 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1094 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1095 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1096 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1097 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1098 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1099 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1100 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1101 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1102 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1103 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1104 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1105 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1106 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1109 int Game_builtin_mission_count = 92;
1110 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1111 // single player campaign
1112 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
1115 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1116 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1117 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1118 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1119 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1120 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1121 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1122 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1123 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1124 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1125 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1126 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1127 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1128 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1129 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1130 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1131 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1132 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1133 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1136 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1137 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1138 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1139 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1140 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1141 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1142 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1143 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1144 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1145 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1148 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1149 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1150 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1151 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1152 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1153 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1154 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1155 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1156 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1157 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1158 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1159 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1161 // multiplayer missions
1164 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1165 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1166 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1169 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1170 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1171 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1172 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1175 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1176 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1177 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1178 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1179 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1180 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1181 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1182 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1183 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1184 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1185 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1186 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1187 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1188 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1189 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1190 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1191 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1192 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1193 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1194 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1195 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1196 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1197 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1198 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1199 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1200 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1201 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1202 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1205 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1206 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1207 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1208 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1209 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1210 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1211 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1212 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1213 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1214 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1217 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1218 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1219 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1220 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1221 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1226 // Internal function prototypes
1227 void game_maybe_draw_mouse(float frametime);
1228 void init_animating_pointer();
1229 void load_animating_pointer(char *filename, int dx, int dy);
1230 void unload_animating_pointer();
1231 void game_do_training_checks();
1232 void game_shutdown(void);
1233 void game_show_event_debug(float frametime);
1234 void game_event_debug_init();
1236 void demo_upsell_show_screens();
1237 void game_start_subspace_ambient_sound();
1238 void game_stop_subspace_ambient_sound();
1239 void verify_ships_tbl();
1240 void verify_weapons_tbl();
1241 void display_title_screen();
1243 // loading background filenames
1244 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1245 "LoadingBG", // GR_640
1246 "2_LoadingBG" // GR_1024
1250 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1251 "Loading.ani", // GR_640
1252 "2_Loading.ani" // GR_1024
1255 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1256 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1264 #elif defined(OEM_BUILD)
1265 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1275 char Game_CDROM_dir[MAX_PATH_LEN];
1278 // How much RAM is on this machine. Set in WinMain
1279 uint Freespace_total_ram = 0;
1282 float Game_flash_red = 0.0f;
1283 float Game_flash_green = 0.0f;
1284 float Game_flash_blue = 0.0f;
1285 float Sun_spot = 0.0f;
1286 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1288 // game shudder stuff (in ms)
1289 int Game_shudder_time = -1;
1290 int Game_shudder_total = 0;
1291 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1294 sound_env Game_sound_env;
1295 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1296 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1298 int Game_sound_env_update_timestamp;
1300 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1303 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1305 fs_builtin_mission *game_find_builtin_mission(char *filename)
1309 // look through all existing builtin missions
1310 for(idx=0; idx<Game_builtin_mission_count; idx++){
1311 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1312 return &Game_builtin_mission_list[idx];
1320 int game_get_default_skill_level()
1322 return DEFAULT_SKILL_LEVEL;
1326 void game_flash_reset()
1328 Game_flash_red = 0.0f;
1329 Game_flash_green = 0.0f;
1330 Game_flash_blue = 0.0f;
1332 Big_expl_flash.max_flash_intensity = 0.0f;
1333 Big_expl_flash.cur_flash_intensity = 0.0f;
1334 Big_expl_flash.flash_start = 0;
1337 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1338 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1340 void game_framerate_check_init()
1342 // zero critical time
1343 Gf_critical_time = 0.0f;
1346 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1347 // if this is a glide card
1348 if(gr_screen.mode == GR_GLIDE){
1350 extern GrHwConfiguration hwconfig;
1353 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1354 Gf_critical = 15.0f;
1358 Gf_critical = 10.0f;
1363 Gf_critical = 15.0f;
1366 // d3d. only care about good cards here I guess (TNT)
1368 Gf_critical = 15.0f;
1371 // if this is a glide card
1372 if(gr_screen.mode == GR_GLIDE){
1374 extern GrHwConfiguration hwconfig;
1377 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1378 Gf_critical = 25.0f;
1382 Gf_critical = 20.0f;
1387 Gf_critical = 25.0f;
1390 // d3d. only care about good cards here I guess (TNT)
1392 Gf_critical = 25.0f;
1397 extern float Framerate;
1398 void game_framerate_check()
1402 // if the current framerate is above the critical level, add frametime
1403 if(Framerate >= Gf_critical){
1404 Gf_critical_time += flFrametime;
1407 if(!Show_framerate){
1411 // display if we're above the critical framerate
1412 if(Framerate < Gf_critical){
1413 gr_set_color_fast(&Color_bright_red);
1414 gr_string(200, y_start, "Framerate warning");
1419 // display our current pct of good frametime
1420 if(f2fl(Missiontime) >= 0.0f){
1421 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1424 gr_set_color_fast(&Color_bright_green);
1426 gr_set_color_fast(&Color_bright_red);
1429 gr_printf(200, y_start, "%d%%", (int)pct);
1436 // Adds a flash effect. These can be positive or negative.
1437 // The range will get capped at around -1 to 1, so stick
1438 // with a range like that.
1439 void game_flash( float r, float g, float b )
1441 Game_flash_red += r;
1442 Game_flash_green += g;
1443 Game_flash_blue += b;
1445 if ( Game_flash_red < -1.0f ) {
1446 Game_flash_red = -1.0f;
1447 } else if ( Game_flash_red > 1.0f ) {
1448 Game_flash_red = 1.0f;
1451 if ( Game_flash_green < -1.0f ) {
1452 Game_flash_green = -1.0f;
1453 } else if ( Game_flash_green > 1.0f ) {
1454 Game_flash_green = 1.0f;
1457 if ( Game_flash_blue < -1.0f ) {
1458 Game_flash_blue = -1.0f;
1459 } else if ( Game_flash_blue > 1.0f ) {
1460 Game_flash_blue = 1.0f;
1465 // Adds a flash for Big Ship explosions
1466 // cap range from 0 to 1
1467 void big_explosion_flash(float flash)
1469 Big_expl_flash.flash_start = timestamp(1);
1473 } else if (flash < 0.0f) {
1477 Big_expl_flash.max_flash_intensity = flash;
1478 Big_expl_flash.cur_flash_intensity = 0.0f;
1481 // Amount to diminish palette towards normal, per second.
1482 #define DIMINISH_RATE 0.75f
1483 #define SUN_DIMINISH_RATE 6.00f
1487 float sn_glare_scale = 1.7f;
1490 dc_get_arg(ARG_FLOAT);
1491 sn_glare_scale = Dc_arg_float;
1494 float Supernova_last_glare = 0.0f;
1495 void game_sunspot_process(float frametime)
1499 float Sun_spot_goal = 0.0f;
1502 sn_stage = supernova_active();
1504 // sunspot differently based on supernova stage
1506 // approaching. player still in control
1509 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1512 light_get_global_dir(&light_dir, 0);
1514 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1517 // scale it some more
1518 dot = dot * (0.5f + (pct * 0.5f));
1521 Sun_spot_goal += (dot * sn_glare_scale);
1524 // draw the sun glow
1525 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1526 // draw the glow for this sun
1527 stars_draw_sun_glow(0);
1530 Supernova_last_glare = Sun_spot_goal;
1533 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1536 Sun_spot_goal = 0.9f;
1537 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1539 if(Sun_spot_goal > 1.0f){
1540 Sun_spot_goal = 1.0f;
1543 Sun_spot_goal *= sn_glare_scale;
1544 Supernova_last_glare = Sun_spot_goal;
1547 // fade to white. display dead popup
1550 Supernova_last_glare += (2.0f * flFrametime);
1551 if(Supernova_last_glare > 2.0f){
1552 Supernova_last_glare = 2.0f;
1555 Sun_spot_goal = Supernova_last_glare;
1562 // check sunspots for all suns
1563 n_lights = light_get_global_count();
1566 for(idx=0; idx<n_lights; idx++){
1567 //(vector *eye_pos, matrix *eye_orient)
1568 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1571 light_get_global_dir(&light_dir, idx);
1573 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1575 Sun_spot_goal += (float)pow(dot,85.0f);
1577 // draw the glow for this sun
1578 stars_draw_sun_glow(idx);
1580 Sun_spot_goal = 0.0f;
1586 Sun_spot_goal = 0.0f;
1590 float dec_amount = frametime*SUN_DIMINISH_RATE;
1592 if ( Sun_spot < Sun_spot_goal ) {
1593 Sun_spot += dec_amount;
1594 if ( Sun_spot > Sun_spot_goal ) {
1595 Sun_spot = Sun_spot_goal;
1597 } else if ( Sun_spot > Sun_spot_goal ) {
1598 Sun_spot -= dec_amount;
1599 if ( Sun_spot < Sun_spot_goal ) {
1600 Sun_spot = Sun_spot_goal;
1606 // Call once a frame to diminish the
1607 // flash effect to 0.
1608 void game_flash_diminish(float frametime)
1610 float dec_amount = frametime*DIMINISH_RATE;
1612 if ( Game_flash_red > 0.0f ) {
1613 Game_flash_red -= dec_amount;
1614 if ( Game_flash_red < 0.0f )
1615 Game_flash_red = 0.0f;
1617 Game_flash_red += dec_amount;
1618 if ( Game_flash_red > 0.0f )
1619 Game_flash_red = 0.0f;
1622 if ( Game_flash_green > 0.0f ) {
1623 Game_flash_green -= dec_amount;
1624 if ( Game_flash_green < 0.0f )
1625 Game_flash_green = 0.0f;
1627 Game_flash_green += dec_amount;
1628 if ( Game_flash_green > 0.0f )
1629 Game_flash_green = 0.0f;
1632 if ( Game_flash_blue > 0.0f ) {
1633 Game_flash_blue -= dec_amount;
1634 if ( Game_flash_blue < 0.0f )
1635 Game_flash_blue = 0.0f;
1637 Game_flash_blue += dec_amount;
1638 if ( Game_flash_blue > 0.0f )
1639 Game_flash_blue = 0.0f;
1642 // update big_explosion_cur_flash
1643 #define TIME_UP 1500
1644 #define TIME_DOWN 2500
1645 int duration = TIME_UP + TIME_DOWN;
1646 int time = timestamp_until(Big_expl_flash.flash_start);
1647 if (time > -duration) {
1649 if (time < TIME_UP) {
1650 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1653 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1657 if ( Use_palette_flash ) {
1659 // static int or=0, og=0, ob=0;
1661 // Change the 200 to change the color range of colors.
1662 r = fl2i( Game_flash_red*128.0f );
1663 g = fl2i( Game_flash_green*128.0f );
1664 b = fl2i( Game_flash_blue*128.0f );
1666 if ( Sun_spot > 0.0f ) {
1667 r += fl2i(Sun_spot*128.0f);
1668 g += fl2i(Sun_spot*128.0f);
1669 b += fl2i(Sun_spot*128.0f);
1672 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1673 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1674 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1675 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1678 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1679 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1680 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1682 if ( (r!=0) || (g!=0) || (b!=0) ) {
1683 gr_flash( r, g, b );
1685 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1696 void game_level_close()
1698 // De-Initialize the game subsystems
1699 event_music_level_close();
1700 game_stop_looped_sounds();
1702 obj_snd_level_close(); // uninit object-linked persistant sounds
1703 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1704 anim_level_close(); // stop and clean up any anim instances
1705 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1706 shockwave_level_close();
1707 fireball_level_close();
1709 mission_event_shutdown();
1710 asteroid_level_close();
1711 model_cache_reset(); // Reset/free all the model caching stuff
1712 flak_level_close(); // unload flak stuff
1713 neb2_level_close(); // shutdown gaseous nebula stuff
1716 mflash_level_close();
1718 audiostream_unpause_all();
1723 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1724 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1725 void game_level_init(int seed)
1727 // seed the random number generator
1729 // if no seed was passed, seed the generator either from the time value, or from the
1730 // netgame security flags -- ensures that all players in multiplayer game will have the
1731 // same randon number sequence (with static rand functions)
1732 if ( Game_mode & GM_NORMAL ) {
1733 Game_level_seed = time(NULL);
1735 Game_level_seed = Netgame.security;
1738 // mwa 9/17/98 -- maybe this assert isn't needed????
1739 Assert( !(Game_mode & GM_MULTIPLAYER) );
1740 Game_level_seed = seed;
1742 srand( Game_level_seed );
1744 // semirand function needs to get re-initted every time in multiplayer
1745 if ( Game_mode & GM_MULTIPLAYER ){
1751 Key_normal_game = (Game_mode & GM_NORMAL);
1754 Game_shudder_time = -1;
1756 // Initialize the game subsystems
1757 // timestamp_reset(); // Must be inited before everything else
1759 game_reset_time(); // resets time, and resets saved time too
1761 obj_init(); // Must be inited before the other systems
1762 model_free_all(); // Free all existing models
1763 mission_brief_common_init(); // Free all existing briefing/debriefing text
1764 weapon_level_init();
1765 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1767 player_level_init();
1768 shipfx_flash_init(); // Init the ship gun flash system.
1769 game_flash_reset(); // Reset the flash effect
1770 particle_init(); // Reset the particle system
1774 shield_hit_init(); // Initialize system for showing shield hits
1775 radar_mission_init();
1776 mission_init_goals();
1779 obj_snd_level_init(); // init object-linked persistant sounds
1781 shockwave_level_init();
1782 afterburner_level_init();
1783 scoring_level_init( &Player->stats );
1785 asteroid_level_init();
1786 control_config_clear_used_status();
1787 collide_ship_ship_sounds_init();
1789 Pre_player_entry = 1; // Means the player has not yet entered.
1790 Entry_delay_time = 0; // Could get overwritten in mission read.
1791 fireball_preload(); // page in warphole bitmaps
1793 flak_level_init(); // initialize flak - bitmaps, etc
1794 ct_level_init(); // initialize ships contrails, etc
1795 awacs_level_init(); // initialize AWACS
1796 beam_level_init(); // initialize beam weapons
1797 mflash_level_init();
1799 supernova_level_init();
1801 // multiplayer dogfight hack
1804 shipfx_engine_wash_level_init();
1808 Last_view_target = NULL;
1813 // campaign wasn't ended
1814 Campaign_ended_in_mission = 0;
1817 // called when a mission is over -- does server specific stuff.
1818 void freespace_stop_mission()
1821 Game_mode &= ~GM_IN_MISSION;
1824 // called at frame interval to process networking stuff
1825 void game_do_networking()
1827 Assert( Net_player != NULL );
1828 if (!(Game_mode & GM_MULTIPLAYER)){
1832 // see if this player should be reading/writing data. Bit is set when at join
1833 // screen onward until quits back to main menu.
1834 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1838 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1841 multi_pause_do_frame();
1846 // Loads the best palette for this level, based
1847 // on nebula color and hud color. You could just call palette_load_table with
1848 // the appropriate filename, but who wants to do that.
1849 void game_load_palette()
1851 char palette_filename[1024];
1853 // We only use 3 hud colors right now
1855 Assert( HUD_config.main_color >= 0 );
1856 Assert( HUD_config.main_color <= 2 );
1859 Assert( Mission_palette >= 0 );
1860 Assert( Mission_palette <= 98 );
1863 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1864 strcpy( palette_filename, NOX("gamepalette-subspace") );
1866 sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1869 mprintf(( "Loading palette %s\n", palette_filename ));
1871 palette_load_table(palette_filename);
1873 strcpy( palette_filename, NOX("gamepalette-subspace") );
1875 mprintf(( "Loading palette %s\n", palette_filename ));
1879 void game_post_level_init()
1881 // Stuff which gets called after mission is loaded. Because player isn't created until
1882 // after mission loads, some things must get initted after the level loads
1884 model_level_post_init();
1887 hud_setup_escort_list();
1888 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1894 game_event_debug_init();
1897 training_mission_init();
1898 asteroid_create_all();
1900 game_framerate_check_init();
1904 // An estimate as to how high the count passed to game_loading_callback will go.
1905 // This is just a guess, it seems to always be about the same. The count is
1906 // proportional to the code being executed, not the time, so this works good
1907 // for a bar, assuming the code does about the same thing each time you
1908 // load a level. You can find this value by looking at the return value
1909 // of game_busy_callback(NULL), which I conveniently print out to the
1910 // debug output window with the '=== ENDING LOAD ==' stuff.
1911 //#define COUNT_ESTIMATE 3706
1912 #define COUNT_ESTIMATE 1111
1914 int Game_loading_callback_inited = 0;
1916 int Game_loading_background = -1;
1917 anim * Game_loading_ani = NULL;
1918 anim_instance *Game_loading_ani_instance;
1919 int Game_loading_frame=-1;
1921 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1923 #if defined(FS1_DEMO)
1925 #elif defined(MAKE_FS1)
1936 // This gets called 10x per second and count is the number of times
1937 // game_busy() has been called since the current callback function
1939 void game_loading_callback(int count)
1941 game_do_networking();
1943 Assert( Game_loading_callback_inited==1 );
1944 Assert( Game_loading_ani != NULL );
1946 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1947 if ( framenum > Game_loading_ani->total_frames-1 ) {
1948 framenum = Game_loading_ani->total_frames-1;
1949 } else if ( framenum < 0 ) {
1954 while ( Game_loading_frame < framenum ) {
1955 Game_loading_frame++;
1956 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1960 if ( cbitmap > -1 ) {
1961 if ( Game_loading_background > -1 ) {
1962 gr_set_bitmap( Game_loading_background );
1966 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1967 gr_set_bitmap( cbitmap );
1968 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1970 bm_release(cbitmap);
1976 void game_loading_callback_init()
1978 Assert( Game_loading_callback_inited==0 );
1980 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1982 common_set_interface_palette("InterfacePalette"); // set the interface palette
1986 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1987 Assert( Game_loading_ani != NULL );
1988 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1989 Assert( Game_loading_ani_instance != NULL );
1990 Game_loading_frame = -1;
1992 Game_loading_callback_inited = 1;
1994 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1999 void game_loading_callback_close()
2001 Assert( Game_loading_callback_inited==1 );
2003 // Make sure bar shows all the way over.
2004 game_loading_callback(COUNT_ESTIMATE);
2006 int real_count = game_busy_callback( NULL );
2009 Game_loading_callback_inited = 0;
2012 mprintf(( "=================== ENDING LOAD ================\n" ));
2013 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
2014 mprintf(( "================================================\n" ));
2016 // to remove warnings in release build
2020 free_anim_instance(Game_loading_ani_instance);
2021 Game_loading_ani_instance = NULL;
2022 anim_free(Game_loading_ani);
2023 Game_loading_ani = NULL;
2025 bm_release( Game_loading_background );
2026 common_free_interface_palette(); // restore game palette
2027 Game_loading_background = -1;
2029 gr_set_font( FONT1 );
2032 // Update the sound environment (ie change EAX settings based on proximity to large ships)
2034 void game_maybe_update_sound_environment()
2036 // do nothing for now
2039 // Assign the sound environment for the game, based on the current mission
2041 void game_assign_sound_environment()
2044 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
2045 Game_sound_env.id = SND_ENV_DRUGGED;
2046 Game_sound_env.volume = 0.800f;
2047 Game_sound_env.damping = 1.188f;
2048 Game_sound_env.decay = 6.392f;
2050 } else if (Num_asteroids > 30) {
2051 Game_sound_env.id = SND_ENV_AUDITORIUM;
2052 Game_sound_env.volume = 0.603f;
2053 Game_sound_env.damping = 0.5f;
2054 Game_sound_env.decay = 4.279f;
2057 Game_sound_env = Game_default_sound_env;
2061 Game_sound_env = Game_default_sound_env;
2062 Game_sound_env_update_timestamp = timestamp(1);
2065 // function which gets called before actually entering the mission. It is broken down into a funciton
2066 // since it will get called in one place from a single player game and from another place for
2067 // a multiplayer game
2068 void freespace_mission_load_stuff()
2070 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2071 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2072 if(!(Game_mode & GM_STANDALONE_SERVER)){
2074 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2076 game_loading_callback_init();
2078 event_music_level_init(); // preloads the first 2 seconds for each event music track
2081 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2084 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2087 ship_assign_sound_all(); // assign engine sounds to ships
2088 game_assign_sound_environment(); // assign the sound environment for this mission
2091 // call function in missionparse.cpp to fixup player/ai stuff.
2092 mission_parse_fixup_players();
2095 // Load in all the bitmaps for this level
2100 game_loading_callback_close();
2102 // the only thing we need to call on the standalone for now.
2104 // call function in missionparse.cpp to fixup player/ai stuff.
2105 mission_parse_fixup_players();
2107 // Load in all the bitmaps for this level
2113 uint load_mission_load;
2114 uint load_post_level_init;
2115 uint load_mission_stuff;
2117 // tells the server to load the mission and initialize structures
2118 int game_start_mission()
2120 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2122 load_gl_init = time(NULL);
2124 load_gl_init = time(NULL) - load_gl_init;
2126 if (Game_mode & GM_MULTIPLAYER) {
2127 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2129 // clear multiplayer stats
2130 init_multiplayer_stats();
2133 load_mission_load = time(NULL);
2134 if (mission_load()) {
2135 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2136 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2137 gameseq_post_event(GS_EVENT_MAIN_MENU);
2139 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2144 load_mission_load = time(NULL) - load_mission_load;
2146 // If this is a red alert mission in campaign mode, bash wingman status
2147 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2148 red_alert_bash_wingman_status();
2151 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2152 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2153 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2155 game_load_palette();
2159 load_post_level_init = time(NULL);
2160 game_post_level_init();
2161 load_post_level_init = time(NULL) - load_post_level_init;
2165 void Do_model_timings_test();
2166 Do_model_timings_test();
2170 load_mission_stuff = time(NULL);
2171 freespace_mission_load_stuff();
2172 load_mission_stuff = time(NULL) - load_mission_stuff;
2177 int Interface_framerate = 0;
2180 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2181 DCF_BOOL( show_framerate, Show_framerate )
2182 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2183 DCF_BOOL( show_target_weapons, Show_target_weapons )
2184 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2185 DCF_BOOL( sound, Sound_enabled )
2186 DCF_BOOL( zbuffer, game_zbuffer )
2187 DCF_BOOL( shield_system, New_shield_system )
2188 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2189 DCF_BOOL( player_attacking, Player_attacking_enabled )
2190 DCF_BOOL( show_waypoints, Show_waypoints )
2191 DCF_BOOL( show_area_effect, Show_area_effect )
2192 DCF_BOOL( show_net_stats, Show_net_stats )
2193 DCF_BOOL( log, Log_debug_output_to_file )
2194 DCF_BOOL( training_msg_method, Training_msg_method )
2195 DCF_BOOL( show_player_pos, Show_player_pos )
2196 DCF_BOOL(i_framerate, Interface_framerate )
2198 DCF(show_mem,"Toggles showing mem usage")
2201 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2202 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2203 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2204 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2210 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2212 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2213 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2217 DCF(show_cpu,"Toggles showing cpu usage")
2220 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2221 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2222 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2223 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2229 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2231 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2232 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2239 // AL 4-8-98: always allow players to display their framerate
2242 DCF_BOOL( show_framerate, Show_framerate )
2249 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2252 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2253 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2254 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2255 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2257 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" );
2258 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2260 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2263 DCF(palette_flash,"Toggles palette flash effect on/off")
2266 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2267 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2268 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2269 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2271 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2272 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2275 int Use_low_mem = 0;
2277 DCF(low_mem,"Uses low memory settings regardless of RAM")
2280 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2281 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2282 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2283 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2285 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2286 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2288 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2294 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2297 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2298 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2299 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2300 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2302 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2303 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2304 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2308 int Framerate_delay = 0;
2310 float Freespace_gamma = 1.0f;
2312 DCF(gamma,"Sets Gamma factor")
2315 dc_get_arg(ARG_FLOAT|ARG_NONE);
2316 if ( Dc_arg_type & ARG_FLOAT ) {
2317 Freespace_gamma = Dc_arg_float;
2319 dc_printf( "Gamma reset to 1.0f\n" );
2320 Freespace_gamma = 1.0f;
2322 if ( Freespace_gamma < 0.1f ) {
2323 Freespace_gamma = 0.1f;
2324 } else if ( Freespace_gamma > 5.0f ) {
2325 Freespace_gamma = 5.0f;
2327 gr_set_gamma(Freespace_gamma);
2329 char tmp_gamma_string[32];
2330 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2331 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2335 dc_printf( "Usage: gamma <float>\n" );
2336 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2337 Dc_status = 0; // don't print status if help is printed. Too messy.
2341 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2350 Game_current_mission_filename[0] = 0;
2352 // seed the random number generator
2353 Game_init_seed = time(NULL);
2354 srand( Game_init_seed );
2356 Framerate_delay = 0;
2362 extern void bm_init();
2368 // Initialize the timer before the os
2376 GetCurrentDirectory(1024, whee);
2379 full_path[strlen(full_path) - strlen(app_path)] = '\0';
2380 strcpy( whee, full_path);
2382 getcwd (whee, 1024);
2385 strcat(whee, EXE_FNAME);
2387 //Initialize the libraries
2388 s1 = timer_get_milliseconds();
2389 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2392 e1 = timer_get_milliseconds();
2394 // time a bunch of cfopens
2396 s2 = timer_get_milliseconds();
2398 for(int idx=0; idx<10000; idx++){
2399 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2404 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2406 e2 = timer_get_milliseconds();
2409 if (Is_standalone) {
2410 std_init_standalone();
2412 os_init( Osreg_class_name, Osreg_app_name );
2413 os_set_title(Osreg_title);
2416 // initialize localization module. Make sure this is down AFTER initialzing OS.
2417 // int t1 = timer_get_milliseconds();
2418 lcl_init( detect_lang() );
2420 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2422 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2425 // verify that he has a valid weapons.tbl
2426 verify_weapons_tbl();
2428 // Output version numbers to registry for auto patching purposes
2429 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2430 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2431 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2433 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2434 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2435 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2438 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2441 #if defined (PLAT_UNIX) && defined(RELEASE_REAL)
2442 // show the FPS counter if the config file says so
2443 Show_framerate = os_config_read_uint( NULL, NOX("ShowFPS"), 0 );
2446 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2447 Asteroids_enabled = 1;
2450 /////////////////////////////
2452 /////////////////////////////
2457 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2458 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2460 if (!stricmp(ptr, NOX("no sound"))) {
2461 Cmdline_freespace_no_sound = 1;
2463 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2465 } else if (!stricmp(ptr, NOX("EAX"))) {
2470 if (!Is_standalone) {
2471 snd_init(use_a3d, use_eax);
2473 /////////////////////////////
2475 /////////////////////////////
2477 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2480 MessageBox((HWND)os_get_window(), XSTR("Please configure your system in the Launcher before running FS2.\n\n The Launcher will now be started!", 1446), XSTR("Attention!", 1447), MB_OK);
2482 // fire up the UpdateLauncher executable
2484 PROCESS_INFORMATION pi;
2486 memset( &si, 0, sizeof(STARTUPINFO) );
2489 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2490 NULL, // pointer to command line string
2491 NULL, // pointer to process security attributes
2492 NULL, // pointer to thread security attributes
2493 FALSE, // handle inheritance flag
2494 CREATE_DEFAULT_ERROR_MODE, // creation flags
2495 NULL, // pointer to new environment block
2496 NULL, // pointer to current directory name
2497 &si, // pointer to STARTUPINFO
2498 &pi // pointer to PROCESS_INFORMATION
2501 // If the Launcher could not be started up, let the user know
2503 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2512 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2514 MessageBox((HWND)os_get_window(), XSTR("Warning, Freespace 2 requires Glide or Direct3D hardware accleration. You will not be able to run Freespace 2 without it.", 1448), XSTR("Warning", 1449), MB_OK);
2522 // check for hi res pack file
2523 int has_sparky_hi = 0;
2525 // check if sparky_hi exists -- access mode 0 means does file exist
2526 #ifndef MAKE_FS1 // shoudn't have it so don't check
2529 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2532 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2536 // see if we've got 32 bit in the string
2537 if(strstr(ptr, "32 bit")){
2544 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2546 // always 640 for E3
2547 gr_init(GR_640, GR_GLIDE);
2549 // regular or hi-res ?
2551 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2553 if(strstr(ptr, NOX("(1024x768)"))){
2555 gr_init(GR_1024, GR_GLIDE);
2557 gr_init(GR_640, GR_GLIDE);
2560 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2562 // always 640 for E3
2564 gr_init(GR_640, GR_DIRECT3D, depth);
2566 // regular or hi-res ?
2568 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2570 if(strstr(ptr, NOX("(1024x768)"))){
2574 gr_init(GR_1024, GR_DIRECT3D, depth);
2578 gr_init(GR_640, GR_DIRECT3D, depth);
2584 if ( Use_fullscreen_at_startup && !Is_standalone) {
2585 gr_init(GR_640, GR_DIRECTDRAW);
2587 gr_init(GR_640, GR_SOFTWARE);
2590 if ( !Is_standalone ) {
2591 gr_init(GR_640, GR_DIRECTDRAW);
2593 gr_init(GR_640, GR_SOFTWARE);
2598 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2599 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2600 gr_init(GR_1024, GR_OPENGL);
2602 gr_init(GR_640, GR_OPENGL);
2606 gr_init(GR_640, GR_SOFTWARE);
2608 #endif // !PLAT_UNIX
2611 extern int Gr_inited;
2612 if(trying_d3d && !Gr_inited){
2614 extern char Device_init_error[512];
2615 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2624 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2625 Freespace_gamma = (float)atof(ptr);
2626 if ( Freespace_gamma == 0.0f ) {
2627 Freespace_gamma = 1.80f;
2628 } else if ( Freespace_gamma < 0.1f ) {
2629 Freespace_gamma = 0.1f;
2630 } else if ( Freespace_gamma > 5.0f ) {
2631 Freespace_gamma = 5.0f;
2633 char tmp_gamma_string[32];
2634 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2635 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2637 gr_set_gamma(Freespace_gamma);
2639 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2642 display_title_screen();
2646 // attempt to load up master tracker registry info (login and password)
2647 Multi_tracker_id = -1;
2649 // pxo login and password
2650 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2652 nprintf(("Network","Error reading in PXO login data\n"));
2653 strcpy(Multi_tracker_login,"");
2655 strcpy(Multi_tracker_login,ptr);
2657 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2659 nprintf(("Network","Error reading PXO password\n"));
2660 strcpy(Multi_tracker_passwd,"");
2662 strcpy(Multi_tracker_passwd,ptr);
2665 // pxo squad name and password
2666 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2668 nprintf(("Network","Error reading in PXO squad name\n"));
2669 strcpy(Multi_tracker_squad_name, "");
2671 strcpy(Multi_tracker_squad_name, ptr);
2674 // If less than 48MB of RAM, use low memory model.
2677 (Freespace_total_ram < 48*1024*1024) ||
2680 mprintf(( "Using normal memory settings...\n" ));
2681 bm_set_low_mem(1); // Use every other frame of bitmaps
2683 mprintf(( "Using high memory settings...\n" ));
2684 bm_set_low_mem(0); // Use all frames of bitmaps
2687 // load non-darkening pixel defs
2688 palman_load_pixels();
2690 // hud shield icon stuff
2691 hud_shield_game_init();
2693 control_config_common_init(); // sets up localization stuff in the control config
2699 gamesnd_parse_soundstbl();
2704 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2709 player_controls_init();
2712 //if(!Is_standalone){
2720 ship_init(); // read in ships.tbl
2722 mission_campaign_init(); // load in the default campaign
2724 // navmap_init(); // init the navigation map system
2725 context_help_init();
2726 techroom_intel_init(); // parse species.tbl, load intel info
2728 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2729 init_animating_pointer();
2731 mission_brief_common_init(); // Mark all the briefing structures as empty.
2732 gr_font_init(); // loads up all fonts
2734 neb2_init(); // fullneb stuff
2738 player_tips_init(); // helpful tips
2741 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2742 pilot_load_pic_list();
2743 pilot_load_squad_pic_list();
2745 load_animating_pointer(NOX("cursor"), 0, 0);
2747 // initialize alpha colors
2748 alpha_colors_init();
2751 // Game_music_paused = 0;
2758 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2759 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2761 mprintf(("cfile_init() took %d\n", e1 - s1));
2762 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2765 char transfer_text[128];
2767 float Start_time = 0.0f;
2769 float Framerate = 0.0f;
2771 float Timing_total = 0.0f;
2772 float Timing_render2 = 0.0f;
2773 float Timing_render3 = 0.0f;
2774 float Timing_flip = 0.0f;
2775 float Timing_clear = 0.0f;
2777 MONITOR(NumPolysDrawn);
2783 void game_get_framerate()
2785 char text[128] = "";
2787 if ( frame_int == -1 ) {
2789 for (i=0; i<FRAME_FILTER; i++ ) {
2790 frametimes[i] = 0.0f;
2795 frametotal -= frametimes[frame_int];
2796 frametotal += flFrametime;
2797 frametimes[frame_int] = flFrametime;
2798 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2800 if ( frametotal != 0.0 ) {
2801 if ( Framecount >= FRAME_FILTER )
2802 Framerate = FRAME_FILTER / frametotal;
2804 Framerate = Framecount / frametotal;
2805 sprintf( text, NOX("FPS: %.1f"), Framerate );
2807 sprintf( text, NOX("FPS: ?") );
2811 if (Show_framerate) {
2812 gr_set_color_fast(&HUD_color_debug);
2813 gr_string( 570, 2, text );
2817 void game_show_framerate()
2821 cur_time = f2fl(timer_get_approx_seconds());
2822 if (cur_time - Start_time > 30.0f) {
2823 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2824 Start_time += 1000.0f;
2827 //mprintf(( "%s\n", text ));
2830 if ( Debug_dump_frames )
2834 // possibly show control checking info
2835 control_check_indicate();
2837 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2838 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2839 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2840 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2843 if ( Show_cpu == 1 ) {
2848 dy = gr_get_font_height() + 1;
2850 gr_set_color_fast(&HUD_color_debug);
2854 extern int D3D_textures_in;
2855 extern int D3D_textures_in_frame;
2856 extern int Glide_textures_in;
2857 extern int Glide_textures_in_frame;
2858 extern int Glide_explosion_vram;
2859 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2861 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2863 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2867 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2869 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2871 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2873 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2875 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2880 extern int Num_pairs; // Number of object pairs that were checked.
2881 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2884 extern int Num_pairs_checked; // What percent of object pairs were checked.
2885 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2887 Num_pairs_checked = 0;
2891 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2894 if ( Timing_total > 0.01f ) {
2895 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2897 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2899 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2901 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2903 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2913 dy = gr_get_font_height() + 1;
2915 gr_set_color_fast(&HUD_color_debug);
2918 extern int TotalRam;
2919 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2924 extern int Model_ram;
2925 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2929 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2931 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2933 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2937 extern int D3D_textures_in;
2938 extern int Glide_textures_in;
2939 extern int Glide_textures_in_frame;
2940 extern int Glide_explosion_vram;
2941 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2943 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2945 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2952 if ( Show_player_pos ) {
2956 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));
2959 MONITOR_INC(NumPolys, modelstats_num_polys);
2960 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2961 MONITOR_INC(NumVerts, modelstats_num_verts );
2963 modelstats_num_polys = 0;
2964 modelstats_num_polys_drawn = 0;
2965 modelstats_num_verts = 0;
2966 modelstats_num_sortnorms = 0;
2970 void game_show_standalone_framerate()
2972 float frame_rate=30.0f;
2973 if ( frame_int == -1 ) {
2975 for (i=0; i<FRAME_FILTER; i++ ) {
2976 frametimes[i] = 0.0f;
2981 frametotal -= frametimes[frame_int];
2982 frametotal += flFrametime;
2983 frametimes[frame_int] = flFrametime;
2984 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2986 if ( frametotal != 0.0 ) {
2987 if ( Framecount >= FRAME_FILTER ){
2988 frame_rate = FRAME_FILTER / frametotal;
2990 frame_rate = Framecount / frametotal;
2993 std_set_standalone_fps(frame_rate);
2997 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2998 void game_show_time_left()
3002 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
3003 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
3004 // checking how much time is left
3006 if ( Mission_end_time == -1 ){
3010 diff = f2i(Mission_end_time - Missiontime);
3011 // be sure to bash to 0. diff could be negative on frame that we quit mission
3016 hud_set_default_color();
3017 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
3020 //========================================================================================
3021 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
3022 //========================================================================================
3026 DCF(ai_pause,"Pauses ai")
3029 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3030 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
3031 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
3032 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
3035 obj_init_all_ships_physics();
3038 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
3039 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
3042 DCF(single_step,"Single steps the game")
3045 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3046 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
3047 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
3048 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
3050 last_single_step = 0; // Make so single step waits a frame before stepping
3053 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
3054 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
3057 DCF_BOOL(physics_pause, physics_paused)
3058 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
3059 DCF_BOOL(ai_firing, Ai_firing_enabled )
3061 // Create some simple aliases to these commands...
3062 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
3063 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
3064 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
3065 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
3066 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
3069 //========================================================================================
3070 //========================================================================================
3073 void game_training_pause_do()
3077 key = game_check_key();
3079 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
3086 void game_increase_skill_level()
3089 if (Game_skill_level >= NUM_SKILL_LEVELS){
3090 Game_skill_level = 0;
3094 int Player_died_time;
3096 int View_percent = 100;
3099 DCF(view, "Sets the percent of the 3d view to render.")
3102 dc_get_arg(ARG_INT);
3103 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
3104 View_percent = Dc_arg_int;
3106 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
3112 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
3116 dc_printf("View is set to %d%%\n", View_percent );
3121 // Set the clip region for the 3d rendering window
3122 void game_set_view_clip()
3124 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
3125 // Set the clip region for the letterbox "dead view"
3126 int yborder = gr_screen.max_h/4;
3128 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
3129 // J.S. I've changed my ways!! See the new "no constants" code!!!
3130 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
3132 // Set the clip region for normal view
3133 if ( View_percent >= 100 ) {
3136 int xborder, yborder;
3138 if ( View_percent < 5 ) {
3142 float fp = i2fl(View_percent)/100.0f;
3143 int fi = fl2i(fl_sqrt(fp)*100.0f);
3144 if ( fi > 100 ) fi=100;
3146 xborder = ( gr_screen.max_w*(100-fi) )/200;
3147 yborder = ( gr_screen.max_h*(100-fi) )/200;
3149 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
3155 void show_debug_stuff()
3158 int laser_count = 0, missile_count = 0;
3160 for (i=0; i<MAX_OBJECTS; i++) {
3161 if (Objects[i].type == OBJ_WEAPON){
3162 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
3164 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
3170 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
3173 extern int Tool_enabled;
3178 int tst_bitmap = -1;
3180 float tst_offset, tst_offset_total;
3183 void game_tst_frame_pre()
3191 g3_rotate_vertex(&v, &tst_pos);
3192 g3_project_vertex(&v);
3195 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
3199 // big ship? always tst
3201 // within 3000 meters
3202 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
3206 // within 300 meters
3207 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
3214 void game_tst_frame()
3224 tst_time = time(NULL);
3226 // load the tst bitmap
3227 switch((int)frand_range(0.0f, 3.0)){
3229 tst_bitmap = bm_load("ig_jim");
3231 mprintf(("TST 0\n"));
3235 tst_bitmap = bm_load("ig_kan");
3237 mprintf(("TST 1\n"));
3241 tst_bitmap = bm_load("ig_jim");
3243 mprintf(("TST 2\n"));
3247 tst_bitmap = bm_load("ig_kan");
3249 mprintf(("TST 3\n"));
3258 // get the tst bitmap dimensions
3260 bm_get_info(tst_bitmap, &w, &h);
3263 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3265 snd_play(&Snds[SND_VASUDAN_BUP]);
3267 // tst x and direction
3271 tst_offset_total = (float)w;
3272 tst_offset = (float)w;
3274 tst_x = (float)gr_screen.max_w;
3275 tst_offset_total = (float)-w;
3276 tst_offset = (float)w;
3284 float diff = (tst_offset_total / 0.5f) * flFrametime;
3290 tst_offset -= fl_abs(diff);
3291 } else if(tst_mode == 2){
3294 tst_offset -= fl_abs(diff);
3298 gr_set_bitmap(tst_bitmap);
3299 gr_bitmap((int)tst_x, (int)tst_y);
3302 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3306 // if we passed the switch point
3307 if(tst_offset <= 0.0f){
3312 tst_stamp = timestamp(1000);
3313 tst_offset = fl_abs(tst_offset_total);
3324 void game_tst_mark(object *objp, ship *shipp)
3333 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3336 sip = &Ship_info[shipp->ship_info_index];
3343 tst_pos = objp->pos;
3344 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3350 extern void render_shields();
3352 void player_repair_frame(float frametime)
3354 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3356 for(idx=0;idx<MAX_PLAYERS;idx++){
3359 np = &Net_players[idx];
3361 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)){
3363 // don't rearm/repair if the player is dead or dying/departing
3364 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3365 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3370 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3371 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3377 #define NUM_FRAMES_TEST 300
3378 #define NUM_MIXED_SOUNDS 16
3379 void do_timing_test(float flFrametime)
3381 static int framecount = 0;
3382 static int test_running = 0;
3383 static float test_time = 0.0f;
3385 static int snds[NUM_MIXED_SOUNDS];
3388 if ( test_running ) {
3390 test_time += flFrametime;
3391 if ( framecount >= NUM_FRAMES_TEST ) {
3393 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3394 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3399 if ( Test_begin == 1 ) {
3405 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3408 // start looping digital sounds
3409 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3410 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3417 DCF(dcf_fov, "Change the field of view")
3420 dc_get_arg(ARG_FLOAT|ARG_NONE);
3421 if ( Dc_arg_type & ARG_NONE ) {
3422 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3423 dc_printf( "Zoom factor reset\n" );
3425 if ( Dc_arg_type & ARG_FLOAT ) {
3426 if (Dc_arg_float < 0.25f) {
3427 Viewer_zoom = 0.25f;
3428 dc_printf("Zoom factor pinned at 0.25.\n");
3429 } else if (Dc_arg_float > 1.25f) {
3430 Viewer_zoom = 1.25f;
3431 dc_printf("Zoom factor pinned at 1.25.\n");
3433 Viewer_zoom = Dc_arg_float;
3439 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3442 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3446 DCF(framerate_cap, "Sets the framerate cap")
3449 dc_get_arg(ARG_INT);
3450 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3451 Framerate_cap = Dc_arg_int;
3453 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3459 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3460 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3461 dc_printf("[n] must be from 1 to 120.\n");
3465 if ( Framerate_cap )
3466 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3468 dc_printf("There is no framerate cap currently active.\n");
3472 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3473 int Show_viewing_from_self = 0;
3475 void say_view_target()
3477 object *view_target;
3479 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3480 view_target = &Objects[Player_ai->target_objnum];
3482 view_target = Player_obj;
3484 if (Game_mode & GM_DEAD) {
3485 if (Player_ai->target_objnum != -1)
3486 view_target = &Objects[Player_ai->target_objnum];
3489 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3490 if (view_target != Player_obj){
3492 char *view_target_name = NULL;
3493 switch(Objects[Player_ai->target_objnum].type) {
3495 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3498 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3499 Viewer_mode &= ~VM_OTHER_SHIP;
3501 case OBJ_JUMP_NODE: {
3502 char jump_node_name[128];
3503 strcpy(jump_node_name, XSTR( "jump node", 184));
3504 view_target_name = jump_node_name;
3505 Viewer_mode &= ~VM_OTHER_SHIP;
3514 if ( view_target_name ) {
3515 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3516 Show_viewing_from_self = 1;
3519 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3520 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3521 Show_viewing_from_self = 1;
3523 if (Show_viewing_from_self)
3524 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3529 Last_view_target = view_target;
3533 float Game_hit_x = 0.0f;
3534 float Game_hit_y = 0.0f;
3536 // Reset at the beginning of each frame
3537 void game_whack_reset()
3543 // Apply a 2d whack to the player
3544 void game_whack_apply( float x, float y )
3546 // Do some force feedback
3547 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3553 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3556 // call to apply a "shudder"
3557 void game_shudder_apply(int time, float intensity)
3559 Game_shudder_time = timestamp(time);
3560 Game_shudder_total = time;
3561 Game_shudder_intensity = intensity;
3564 #define FF_SCALE 10000
3565 void apply_hud_shake(matrix *eye_orient)
3567 if (Viewer_obj == Player_obj) {
3568 physics_info *pi = &Player_obj->phys_info;
3576 // Make eye shake due to afterburner
3577 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3580 dtime = timestamp_until(pi->afterburner_decay);
3584 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3585 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3588 // Make eye shake due to engine wash
3590 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3593 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3594 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3596 // get the intensity
3597 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3601 vm_vec_rand_vec_quick(&rand_vec);
3604 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3608 // make hud shake due to shuddering
3609 if(Game_shudder_time != -1){
3610 // if the timestamp has elapsed
3611 if(timestamp_elapsed(Game_shudder_time)){
3612 Game_shudder_time = -1;
3614 // otherwise apply some shudder
3618 dtime = timestamp_until(Game_shudder_time);
3622 tangles.p += (Game_shudder_intensity / 200.0f) * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3623 tangles.h += (Game_shudder_intensity / 200.0f) * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3628 vm_angles_2_matrix(&tm, &tangles);
3629 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3630 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3631 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3632 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3637 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3639 // Player's velocity just before he blew up. Used to keep camera target moving.
3640 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3642 // Set eye_pos and eye_orient based on view mode.
3643 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3647 static int last_Viewer_mode = 0;
3648 static int last_Game_mode = 0;
3649 static int last_Viewer_objnum = -1;
3651 // This code is supposed to detect camera "cuts"... like going between
3654 // determine if we need to regenerate the nebula
3655 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3656 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3657 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3658 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3659 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3660 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3661 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3662 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3663 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3666 // regenerate the nebula
3670 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3671 //mprintf(( "************** Camera cut! ************\n" ));
3672 last_Viewer_mode = Viewer_mode;
3673 last_Game_mode = Game_mode;
3675 // Camera moved. Tell stars & debris to not do blurring.
3681 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3682 player_display_packlock_view();
3685 game_set_view_clip();
3687 if (Game_mode & GM_DEAD) {
3688 vector vec_to_deader, view_pos;
3691 Viewer_mode |= VM_DEAD_VIEW;
3693 if (Player_ai->target_objnum != -1) {
3694 int view_from_player = 1;
3696 if (Viewer_mode & VM_OTHER_SHIP) {
3697 // View from target.
3698 Viewer_obj = &Objects[Player_ai->target_objnum];
3700 last_Viewer_objnum = Player_ai->target_objnum;
3702 if ( Viewer_obj->type == OBJ_SHIP ) {
3703 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3704 view_from_player = 0;
3707 last_Viewer_objnum = -1;
3710 if ( view_from_player ) {
3711 // View target from player ship.
3713 *eye_pos = Player_obj->pos;
3714 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3715 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3718 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3720 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3721 dist += flFrametime * 16.0f;
3723 vm_vec_scale(&vec_to_deader, -dist);
3724 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3726 view_pos = Player_obj->pos;
3728 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3729 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3730 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3731 Dead_player_last_vel = Player_obj->phys_info.vel;
3732 //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));
3733 } else if (Player_ai->target_objnum != -1) {
3734 view_pos = Objects[Player_ai->target_objnum].pos;
3736 // Make camera follow explosion, but gradually slow down.
3737 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3738 view_pos = Player_obj->pos;
3739 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3740 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3743 *eye_pos = Dead_camera_pos;
3745 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3747 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3752 // if supernova shockwave
3753 if(supernova_camera_cut()){
3757 // call it dead view
3758 Viewer_mode |= VM_DEAD_VIEW;
3760 // set eye pos and orient
3761 supernova_set_view(eye_pos, eye_orient);
3763 // If already blown up, these other modes can override.
3764 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3765 Viewer_mode &= ~VM_DEAD_VIEW;
3767 Viewer_obj = Player_obj;
3769 if (Viewer_mode & VM_OTHER_SHIP) {
3770 if (Player_ai->target_objnum != -1){
3771 Viewer_obj = &Objects[Player_ai->target_objnum];
3772 last_Viewer_objnum = Player_ai->target_objnum;
3774 Viewer_mode &= ~VM_OTHER_SHIP;
3775 last_Viewer_objnum = -1;
3778 last_Viewer_objnum = -1;
3781 if (Viewer_mode & VM_EXTERNAL) {
3784 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3785 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3787 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3789 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3790 vm_vec_normalize(&eye_dir);
3791 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3794 // Modify the orientation based on head orientation.
3795 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3797 } else if ( Viewer_mode & VM_CHASE ) {
3800 if ( Viewer_obj->phys_info.speed < 0.1 )
3801 move_dir = Viewer_obj->orient.v.fvec;
3803 move_dir = Viewer_obj->phys_info.vel;
3804 vm_vec_normalize(&move_dir);
3807 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3808 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3809 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3810 vm_vec_normalize(&eye_dir);
3812 // JAS: I added the following code because if you slew up using
3813 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3814 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3815 // call because the up and the forward vector are the same. I fixed
3816 // it by adding in a fraction of the right vector all the time to the
3818 vector tmp_up = Viewer_obj->orient.v.uvec;
3819 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3821 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3824 // Modify the orientation based on head orientation.
3825 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3826 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3827 *eye_pos = Camera_pos;
3829 ship * shipp = &Ships[Player_obj->instance];
3831 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3832 vm_vec_normalize(&eye_dir);
3833 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3836 // get an eye position based upon the correct type of object
3837 switch(Viewer_obj->type){
3839 // make a call to get the eye point for the player object
3840 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3843 // make a call to get the eye point for the player object
3844 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3850 #ifdef JOHNS_DEBUG_CODE
3851 john_debug_stuff(&eye_pos, &eye_orient);
3857 apply_hud_shake(eye_orient);
3859 // setup neb2 rendering
3860 neb2_render_setup(eye_pos, eye_orient);
3864 extern void ai_debug_render_stuff();
3867 int Game_subspace_effect = 0;
3868 DCF_BOOL( subspace, Game_subspace_effect );
3870 // Does everything needed to render a frame
3871 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3875 g3_start_frame(game_zbuffer);
3876 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3878 // maybe offset the HUD (jitter stuff)
3879 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3880 HUD_set_offsets(Viewer_obj, !dont_offset);
3882 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3883 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3884 // must be done before ships are rendered
3885 if ( MULTIPLAYER_CLIENT ) {
3886 shield_point_multi_setup();
3889 if ( Game_subspace_effect ) {
3890 stars_draw(0,0,0,1);
3892 stars_draw(1,1,1,0);
3895 obj_render_all(obj_render);
3896 beam_render_all(); // render all beam weapons
3897 particle_render_all(); // render particles after everything else.
3898 trail_render_all(); // render missilie trails after everything else.
3899 mflash_render_all(); // render all muzzle flashes
3901 // Why do we not show the shield effect in these modes? Seems ok.
3902 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3906 // render nebula lightning
3909 // render local player nebula
3910 neb2_render_player();
3913 ai_debug_render_stuff();
3916 #ifndef RELEASE_REAL
3917 // game_framerate_check();
3921 extern void snd_spew_debug_info();
3922 snd_spew_debug_info();
3925 //================ END OF 3D RENDERING STUFF ====================
3929 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3930 hud_maybe_clear_head_area();
3931 anim_render_all(0, flFrametime);
3934 extern int Multi_display_netinfo;
3935 if(Multi_display_netinfo){
3936 extern void multi_display_netinfo();
3937 multi_display_netinfo();
3940 game_tst_frame_pre();
3943 do_timing_test(flFrametime);
3947 extern int OO_update_index;
3948 multi_rate_display(OO_update_index, 375, 0);
3953 extern void oo_display();
3960 //#define JOHNS_DEBUG_CODE 1
3962 #ifdef JOHNS_DEBUG_CODE
3963 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3965 //if ( keyd_pressed[KEY_LSHIFT] )
3967 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3969 model_subsystem *turret = tsys->system_info;
3971 if (turret->type == SUBSYSTEM_TURRET ) {
3972 vector v.fvec, v.uvec;
3973 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3975 ship_model_start(tobj);
3977 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3978 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3979 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3981 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3983 ship_model_stop(tobj);
3993 // following function for dumping frames for purposes of building trailers.
3996 // function to toggle state of dumping every frame into PCX when playing the game
3997 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
4001 if ( Debug_dump_frames == 0 ) {
4003 Debug_dump_frames = 15;
4004 Debug_dump_trigger = 0;
4005 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4006 dc_printf( "Frame dumping at 15 hz is now ON\n" );
4009 Debug_dump_frames = 0;
4010 Debug_dump_trigger = 0;
4011 gr_dump_frame_stop();
4012 dc_printf( "Frame dumping is now OFF\n" );
4018 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
4022 if ( Debug_dump_frames == 0 ) {
4024 Debug_dump_frames = 15;
4025 Debug_dump_trigger = 1;
4026 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4027 dc_printf( "Frame dumping at 15 hz is now ON\n" );
4030 Debug_dump_frames = 0;
4031 Debug_dump_trigger = 0;
4032 gr_dump_frame_stop();
4033 dc_printf( "Frame dumping is now OFF\n" );
4039 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
4043 if ( Debug_dump_frames == 0 ) {
4045 Debug_dump_frames = 30;
4046 Debug_dump_trigger = 0;
4047 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4048 dc_printf( "Frame dumping at 30 hz is now ON\n" );
4051 Debug_dump_frames = 0;
4052 Debug_dump_trigger = 0;
4053 gr_dump_frame_stop();
4054 dc_printf( "Frame dumping is now OFF\n" );
4060 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
4064 if ( Debug_dump_frames == 0 ) {
4066 Debug_dump_frames = 30;
4067 Debug_dump_trigger = 1;
4068 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4069 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
4072 Debug_dump_frames = 0;
4073 Debug_dump_trigger = 0;
4074 gr_dump_frame_stop();
4075 dc_printf( "Triggered frame dumping is now OFF\n" );
4081 void game_maybe_dump_frame()
4083 if ( !Debug_dump_frames ){
4087 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
4094 Debug_dump_frame_num++;
4100 extern int Player_dead_state;
4102 // Flip the page and time how long it took.
4103 void game_flip_page_and_time_it()
4108 t1 = timer_get_fixed_seconds();
4110 t2 = timer_get_fixed_seconds();
4113 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
4114 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
4121 void game_simulation_frame()
4123 // blow ships up in multiplayer dogfight
4124 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){
4125 // blow up all non-player ships
4126 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
4129 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
4131 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)){
4132 moveup = GET_NEXT(moveup);
4135 shipp = &Ships[Objects[moveup->objnum].instance];
4136 sip = &Ship_info[shipp->ship_info_index];
4138 // only blow up small ships
4139 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
4140 // function to simply explode a ship where it is currently at
4141 ship_self_destruct( &Objects[moveup->objnum] );
4144 moveup = GET_NEXT(moveup);
4150 // process AWACS stuff - do this first thing
4153 // single player, set Player hits_this_frame to 0
4154 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
4155 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
4156 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
4160 supernova_process();
4161 if(supernova_active() >= 5){
4165 // fire targeting lasers now so that
4166 // 1 - created this frame
4167 // 2 - collide this frame
4168 // 3 - render this frame
4169 // 4 - ignored and deleted next frame
4170 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
4172 ship_process_targeting_lasers();
4174 // do this here so that it works for multiplayer
4176 // get viewer direction
4177 int viewer_direction = PHYSICS_VIEWER_REAR;
4179 if(Viewer_mode == 0){
4180 viewer_direction = PHYSICS_VIEWER_FRONT;
4182 if(Viewer_mode & VM_PADLOCK_UP){
4183 viewer_direction = PHYSICS_VIEWER_UP;
4185 else if(Viewer_mode & VM_PADLOCK_REAR){
4186 viewer_direction = PHYSICS_VIEWER_REAR;
4188 else if(Viewer_mode & VM_PADLOCK_LEFT){
4189 viewer_direction = PHYSICS_VIEWER_LEFT;
4191 else if(Viewer_mode & VM_PADLOCK_RIGHT){
4192 viewer_direction = PHYSICS_VIEWER_RIGHT;
4195 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
4197 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
4200 #define VM_PADLOCK_UP (1 << 7)
4201 #define VM_PADLOCK_REAR (1 << 8)
4202 #define VM_PADLOCK_LEFT (1 << 9)
4203 #define VM_PADLOCK_RIGHT (1 << 10)
4205 // evaluate mission departures and arrivals before we process all objects.
4206 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
4208 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
4209 // ships/wing packets.
4210 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
4211 mission_parse_eval_stuff();
4214 // if we're an observer, move ourselves seperately from the standard physics
4215 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
4216 obj_observer_move(flFrametime);
4219 // move all the objects now
4220 obj_move_all(flFrametime);
4222 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
4223 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
4224 // ship_check_cargo_all();
4225 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4226 mission_eval_goals();
4230 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
4231 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4232 training_check_objectives();
4235 // do all interpolation now
4236 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
4237 // client side processing of warping in effect stages
4238 multi_do_client_warp(flFrametime);
4240 // client side movement of an observer
4241 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
4242 obj_observer_move(flFrametime);
4245 // move all objects - does interpolation now as well
4246 obj_move_all(flFrametime);
4249 // only process the message queue when the player is "in" the game
4250 if ( !Pre_player_entry ){
4251 message_queue_process(); // process any messages send to the player
4254 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4255 message_maybe_distort(); // maybe distort incoming message if comms damaged
4256 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4257 player_process_pending_praise(); // maybe send off a delayed praise message to the player
4258 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4261 if(!(Game_mode & GM_STANDALONE_SERVER)){
4262 // process some stuff every frame (before frame is rendered)
4263 emp_process_local();
4265 hud_update_frame(); // update hud systems
4267 if (!physics_paused) {
4268 // Move particle system
4269 particle_move_all(flFrametime);
4271 // Move missile trails
4272 trail_move_all(flFrametime);
4274 // process muzzle flashes
4275 mflash_process_all();
4277 // Flash the gun flashes
4278 shipfx_flash_do_frame(flFrametime);
4280 shockwave_move_all(flFrametime); // update all the shockwaves
4283 // subspace missile strikes
4286 obj_snd_do_frame(); // update the object-linked persistant sounds
4287 game_maybe_update_sound_environment();
4288 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4290 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4292 if ( Game_subspace_effect ) {
4293 game_start_subspace_ambient_sound();
4299 // Maybe render and process the dead-popup
4300 void game_maybe_do_dead_popup(float frametime)
4302 if ( popupdead_is_active() ) {
4304 int choice = popupdead_do_frame(frametime);
4306 if ( Game_mode & GM_NORMAL ) {
4310 if(game_do_cd_mission_check(Game_current_mission_filename)){
4311 gameseq_post_event(GS_EVENT_ENTER_GAME);
4313 gameseq_post_event(GS_EVENT_MAIN_MENU);
4318 gameseq_post_event(GS_EVENT_END_GAME);
4323 if(game_do_cd_mission_check(Game_current_mission_filename)){
4324 gameseq_post_event(GS_EVENT_START_GAME);
4326 gameseq_post_event(GS_EVENT_MAIN_MENU);
4330 // this should only happen during a red alert mission
4333 Assert(The_mission.red_alert);
4334 if(!The_mission.red_alert){
4336 if(game_do_cd_mission_check(Game_current_mission_filename)){
4337 gameseq_post_event(GS_EVENT_START_GAME);
4339 gameseq_post_event(GS_EVENT_MAIN_MENU);
4344 // choose the previous mission
4345 mission_campaign_previous_mission();
4347 if(game_do_cd_mission_check(Game_current_mission_filename)){
4348 gameseq_post_event(GS_EVENT_START_GAME);
4350 gameseq_post_event(GS_EVENT_MAIN_MENU);
4361 case POPUPDEAD_DO_MAIN_HALL:
4362 multi_quit_game(PROMPT_NONE,-1);
4365 case POPUPDEAD_DO_RESPAWN:
4366 multi_respawn_normal();
4367 event_music_player_respawn();
4370 case POPUPDEAD_DO_OBSERVER:
4371 multi_respawn_observer();
4372 event_music_player_respawn_as_observer();
4381 if ( leave_popup ) {
4387 // returns true if player is actually in a game_play stats
4388 int game_actually_playing()
4392 state = gameseq_get_state();
4393 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4399 // Draw the 2D HUD gauges
4400 void game_render_hud_2d()
4402 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4406 HUD_render_2d(flFrametime);
4410 // Draw the 3D-dependant HUD gauges
4411 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4413 g3_start_frame(0); // 0 = turn zbuffering off
4414 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4416 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4417 HUD_render_3d(flFrametime);
4421 game_sunspot_process(flFrametime);
4423 // Diminish the palette effect
4424 game_flash_diminish(flFrametime);
4432 int actually_playing;
4433 fix total_time1, total_time2;
4434 fix render2_time1=0, render2_time2=0;
4435 fix render3_time1=0, render3_time2=0;
4436 fix flip_time1=0, flip_time2=0;
4437 fix clear_time1=0, clear_time2=0;
4443 if (Framerate_delay) {
4444 int start_time = timer_get_milliseconds();
4445 while (timer_get_milliseconds() < start_time + Framerate_delay)
4451 demo_do_frame_start();
4453 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4458 // start timing frame
4459 timing_frame_start();
4461 total_time1 = timer_get_fixed_seconds();
4463 // var to hold which state we are in
4464 actually_playing = game_actually_playing();
4466 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4467 if (!(Game_mode & GM_STANDALONE_SERVER)){
4468 Assert( OBJ_INDEX(Player_obj) >= 0 );
4472 if (Missiontime > Entry_delay_time){
4473 Pre_player_entry = 0;
4475 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4478 // Note: These are done even before the player enters, else buffers can overflow.
4479 if (! (Game_mode & GM_STANDALONE_SERVER)){
4483 shield_frame_init();
4485 if ( Player->control_mode != PCM_NORMAL )
4488 if ( !Pre_player_entry && actually_playing ) {
4489 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4491 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4492 game_process_keys();
4494 // don't read flying controls if we're playing a demo back
4495 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4496 read_player_controls( Player_obj, flFrametime);
4500 // if we're not the master, we may have to send the server-critical ship status button_info bits
4501 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4502 multi_maybe_send_ship_status();
4507 // Reset the whack stuff
4510 // These two lines must be outside of Pre_player_entry code,
4511 // otherwise too many lights are added.
4514 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4518 game_simulation_frame();
4520 // if not actually in a game play state, then return. This condition could only be true in
4521 // a multiplayer game.
4522 if ( !actually_playing ) {
4523 Assert( Game_mode & GM_MULTIPLAYER );
4527 if (!Pre_player_entry) {
4528 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4529 clear_time1 = timer_get_fixed_seconds();
4530 // clear the screen to black
4532 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4536 clear_time2 = timer_get_fixed_seconds();
4537 render3_time1 = timer_get_fixed_seconds();
4538 game_render_frame_setup(&eye_pos, &eye_orient);
4539 game_render_frame( &eye_pos, &eye_orient );
4541 // save the eye position and orientation
4542 if ( Game_mode & GM_MULTIPLAYER ) {
4543 Net_player->s_info.eye_pos = eye_pos;
4544 Net_player->s_info.eye_orient = eye_orient;
4547 hud_show_target_model();
4549 // check to see if we should display the death died popup
4550 if(Game_mode & GM_DEAD_BLEW_UP){
4551 if(Game_mode & GM_MULTIPLAYER){
4552 // catch the situation where we're supposed to be warping out on this transition
4553 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4554 gameseq_post_event(GS_EVENT_DEBRIEF);
4555 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4556 Player_died_popup_wait = -1;
4560 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4561 Player_died_popup_wait = -1;
4567 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4568 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4569 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4570 if(!popupdead_is_active()){
4574 Player_multi_died_check = -1;
4578 render3_time2 = timer_get_fixed_seconds();
4579 render2_time1 = timer_get_fixed_seconds();
4582 game_get_framerate();
4583 game_show_framerate();
4585 game_show_time_left();
4587 // Draw the 2D HUD gauges
4588 if(supernova_active() < 3){
4589 game_render_hud_2d();
4592 game_set_view_clip();
4594 // Draw 3D HUD gauges
4595 game_render_hud_3d(&eye_pos, &eye_orient);
4599 render2_time2 = timer_get_fixed_seconds();
4601 // maybe render and process the dead popup
4602 game_maybe_do_dead_popup(flFrametime);
4604 // start timing frame
4605 timing_frame_stop();
4606 // timing_display(30, 10);
4608 // If a regular popup is active, don't flip (popup code flips)
4609 if( !popup_running_state() ){
4610 flip_time1 = timer_get_fixed_seconds();
4611 game_flip_page_and_time_it();
4612 flip_time2 = timer_get_fixed_seconds();
4616 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4619 game_show_standalone_framerate();
4623 game_do_training_checks();
4626 // process lightning (nebula only)
4629 total_time2 = timer_get_fixed_seconds();
4631 // Got some timing numbers
4632 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4633 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4634 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4635 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4636 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4639 demo_do_frame_end();
4641 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4647 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4648 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4649 // died. This resulted in screwed up death sequences.
4651 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4652 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4653 static int timer_paused=0;
4654 #if defined(TIMER_TEST) && !defined(NDEBUG)
4655 static int stop_count,start_count;
4656 static int time_stopped,time_started;
4658 int saved_timestamp_ticker = -1;
4660 void game_reset_time()
4662 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4666 // Last_time = timer_get_fixed_seconds();
4672 void game_stop_time()
4674 if (timer_paused==0) {
4676 time = timer_get_fixed_seconds();
4677 // Save how much time progressed so far in the frame so we can
4678 // use it when we unpause.
4679 Last_delta_time = time - Last_time;
4681 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4682 if (Last_delta_time < 0) {
4683 #if defined(TIMER_TEST) && !defined(NDEBUG)
4684 Int3(); //get Matt!!!!
4686 Last_delta_time = 0;
4688 #if defined(TIMER_TEST) && !defined(NDEBUG)
4689 time_stopped = time;
4692 // Stop the timer_tick stuff...
4693 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4694 saved_timestamp_ticker = timestamp_ticker;
4698 #if defined(TIMER_TEST) && !defined(NDEBUG)
4703 void game_start_time()
4706 Assert(timer_paused >= 0);
4707 if (timer_paused==0) {
4709 time = timer_get_fixed_seconds();
4710 #if defined(TIMER_TEST) && !defined(NDEBUG)
4712 Int3(); //get Matt!!!!
4715 // Take current time, and set it backwards to account for time
4716 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4717 // will be correct when it goes to calculate the frametime next
4719 Last_time = time - Last_delta_time;
4720 #if defined(TIMER_TEST) && !defined(NDEBUG)
4721 time_started = time;
4724 // Restore the timer_tick stuff...
4725 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4726 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4727 timestamp_ticker = saved_timestamp_ticker;
4728 saved_timestamp_ticker = -1;
4731 #if defined(TIMER_TEST) && !defined(NDEBUG)
4737 void game_set_frametime(int state)
4740 float frame_cap_diff;
4742 thistime = timer_get_fixed_seconds();
4744 if ( Last_time == 0 )
4745 Frametime = F1_0 / 30;
4747 Frametime = thistime - Last_time;
4749 // Frametime = F1_0 / 30;
4751 fix debug_frametime = Frametime; // Just used to display frametime.
4753 // If player hasn't entered mission yet, make frame take 1/4 second.
4754 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4757 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4759 fix frame_speed = F1_0 / Debug_dump_frames;
4761 if (Frametime > frame_speed ){
4762 nprintf(("warning","slow frame: %x\n",Frametime));
4765 thistime = timer_get_fixed_seconds();
4766 Frametime = thistime - Last_time;
4767 } while (Frametime < frame_speed );
4769 Frametime = frame_speed;
4773 Assert( Framerate_cap > 0 );
4775 // Cap the framerate so it doesn't get too high.
4779 cap = F1_0/Framerate_cap;
4780 if (Frametime < cap) {
4781 thistime = cap - Frametime;
4782 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4783 Sleep( (DWORD)(f2fl(thistime) * 1000.0f) );
4785 thistime = timer_get_fixed_seconds();
4789 if((Game_mode & GM_STANDALONE_SERVER) &&
4790 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4792 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4793 Sleep((DWORD)(frame_cap_diff*1000));
4795 thistime += fl2f((frame_cap_diff));
4797 Frametime = thistime - Last_time;
4800 // If framerate is too low, cap it.
4801 if (Frametime > MAX_FRAMETIME) {
4803 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4805 // to remove warnings in release build
4806 debug_frametime = fl2f(flFrametime);
4808 Frametime = MAX_FRAMETIME;
4811 Frametime = fixmul(Frametime, Game_time_compression);
4813 Last_time = thistime;
4814 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4816 flFrametime = f2fl(Frametime);
4817 //if(!(Game_mode & GM_PLAYING_DEMO)){
4818 timestamp_inc(flFrametime);
4820 /* if ((Framecount > 0) && (Framecount < 10)) {
4821 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4826 // This is called from game_do_frame(), and from navmap_do_frame()
4827 void game_update_missiontime()
4829 // TODO JAS: Put in if and move this into game_set_frametime,
4830 // fix navmap to call game_stop/start_time
4831 //if ( !timer_paused )
4832 Missiontime += Frametime;
4835 void game_do_frame()
4837 game_set_frametime(GS_STATE_GAME_PLAY);
4838 game_update_missiontime();
4840 if (Game_mode & GM_STANDALONE_SERVER) {
4841 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4844 if ( game_single_step && (last_single_step == game_single_step) ) {
4845 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4846 while( key_checkch() == 0 )
4848 os_set_title( XSTR( "FreeSpace", 171) );
4849 Last_time = timer_get_fixed_seconds();
4852 last_single_step = game_single_step;
4854 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4855 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4859 Keep_mouse_centered = 0;
4860 monitor_update(); // Update monitor variables
4863 void multi_maybe_do_frame()
4865 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4870 int Joymouse_button_status = 0;
4872 // Flush all input devices
4880 Joymouse_button_status = 0;
4882 //mprintf(("Game flush!\n" ));
4885 // function for multiplayer only which calls game_do_state_common() when running the
4887 void game_do_dc_networking()
4889 Assert( Game_mode & GM_MULTIPLAYER );
4891 game_do_state_common( gameseq_get_state() );
4894 // Call this whenever in a loop, or when you need to check for a keystroke.
4895 int game_check_key()
4901 // convert keypad enter to normal enter
4902 if ((k & KEY_MASK) == KEY_PADENTER)
4903 k = (k & ~KEY_MASK) | KEY_ENTER;
4908 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4910 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4911 static int Demo_show_trailer_timestamp = 0;
4913 void demo_reset_trailer_timer()
4915 Demo_show_trailer_timestamp = timer_get_milliseconds();
4918 void demo_maybe_show_trailer(int k)
4921 // if key pressed, reset demo trailer timer
4923 demo_reset_trailer_timer();
4927 // if mouse moved, reset demo trailer timer
4930 mouse_get_delta(&dx, &dy);
4931 if ( (dx > 0) || (dy > 0) ) {
4932 demo_reset_trailer_timer();
4936 // if joystick has moved, reset demo trailer timer
4939 joy_get_delta(&dx, &dy);
4940 if ( (dx > 0) || (dy > 0) ) {
4941 demo_reset_trailer_timer();
4945 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4946 // the low-level code. Ugly, I know... but was the simplest and most
4949 // if 30 seconds since last demo trailer time reset, launch movie
4950 if ( os_foreground() ) {
4951 int now = timer_get_milliseconds();
4952 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4953 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4955 movie_play( NOX("fstrailer2.mve") );
4956 demo_reset_trailer_timer();
4964 // same as game_check_key(), except this is used while actually in the game. Since there
4965 // generally are differences between game control keys and general UI keys, makes sense to
4966 // have seperate functions for each case. If you are not checking a game control while in a
4967 // mission, you should probably be using game_check_key() instead.
4972 if (!os_foreground()) {
4977 // If we're in a single player game, pause it.
4978 if (!(Game_mode & GM_MULTIPLAYER)){
4979 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4980 game_process_pause_key();
4987 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4988 demo_maybe_show_trailer(k);
4991 // Move the mouse cursor with the joystick.
4992 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4993 // Move the mouse cursor with the joystick
4997 joy_get_pos( &jx, &jy, &jz, &jr );
4999 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
5000 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
5003 mouse_get_real_pos( &mx, &my );
5004 mouse_set_pos( mx+dx, my+dy );
5009 m = mouse_down(MOUSE_LEFT_BUTTON);
5011 if ( j != Joymouse_button_status ) {
5012 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
5013 Joymouse_button_status = j;
5015 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
5016 } else if ( (!j) && (m) ) {
5017 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
5022 // if we should be ignoring keys because of some multiplayer situations
5023 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
5027 // If a popup is running, don't process all the Fn keys
5028 if( popup_active() ) {
5032 state = gameseq_get_state();
5034 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
5037 case KEY_DEBUGGED + KEY_BACKSP:
5042 launch_context_help();
5047 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
5049 // don't allow f2 while warping out in multiplayer
5050 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
5055 case GS_STATE_INITIAL_PLAYER_SELECT:
5056 case GS_STATE_OPTIONS_MENU:
5057 case GS_STATE_HUD_CONFIG:
5058 case GS_STATE_CONTROL_CONFIG:
5059 case GS_STATE_DEATH_DIED:
5060 case GS_STATE_DEATH_BLEW_UP:
5061 case GS_STATE_VIEW_MEDALS:
5065 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
5072 // hotkey selection screen -- only valid from briefing and beyond.
5074 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
5075 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) ) {
5076 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
5082 case KEY_DEBUGGED + KEY_F3:
5083 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
5086 case KEY_DEBUGGED + KEY_F4:
5087 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
5091 if(Game_mode & GM_MULTIPLAYER){
5092 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
5093 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5097 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
5098 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5104 case KEY_ESC | KEY_SHIFTED:
5105 // make sure to quit properly out of multiplayer
5106 if(Game_mode & GM_MULTIPLAYER){
5107 multi_quit_game(PROMPT_NONE);
5110 gameseq_post_event( GS_EVENT_QUIT_GAME );
5115 case KEY_DEBUGGED + KEY_P:
5118 case KEY_PRINT_SCRN:
5120 static int counter = 0;
5125 sprintf( tmp_name, NOX("screen%02d"), counter );
5127 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
5128 gr_print_screen(tmp_name);
5136 case KEY_SHIFTED | KEY_ENTER: {
5138 #if !defined(NDEBUG)
5140 if ( Game_mode & GM_NORMAL ){
5144 // if we're in multiplayer mode, do some special networking
5145 if(Game_mode & GM_MULTIPLAYER){
5146 debug_console(game_do_dc_networking);
5153 if ( Game_mode & GM_NORMAL )
5167 gameseq_post_event(GS_EVENT_QUIT_GAME);
5170 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
5173 void camera_set_position( vector *pos )
5178 void camera_set_orient( matrix *orient )
5180 Camera_orient = *orient;
5183 void camera_set_velocity( vector *vel, int instantaneous )
5185 Camera_desired_velocity.xyz.x = 0.0f;
5186 Camera_desired_velocity.xyz.y = 0.0f;
5187 Camera_desired_velocity.xyz.z = 0.0f;
5189 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
5190 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
5191 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
5193 if ( instantaneous ) {
5194 Camera_velocity = Camera_desired_velocity;
5202 vector new_vel, delta_pos;
5204 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
5205 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
5206 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
5208 Camera_velocity = new_vel;
5210 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
5212 vm_vec_add2( &Camera_pos, &delta_pos );
5214 float ot = Camera_time+0.0f;
5216 Camera_time += flFrametime;
5218 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
5221 tmp.xyz.z = 4.739f; // always go this fast forward.
5223 // pick x and y velocities so they are always on a
5224 // circle with a 25 m radius.
5226 float tmp_angle = frand()*PI2;
5228 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
5229 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
5231 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
5233 //mprintf(( "Changing velocity!\n" ));
5234 camera_set_velocity( &tmp, 0 );
5237 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
5238 vector tmp = { 0.0f, 0.0f, 0.0f };
5239 camera_set_velocity( &tmp, 0 );
5244 void end_demo_campaign_do()
5246 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5247 // show upsell screens
5248 demo_upsell_show_screens();
5249 #elif defined(OEM_BUILD)
5250 // show oem upsell screens
5251 oem_upsell_show_screens();
5254 // drop into main hall
5255 gameseq_post_event( GS_EVENT_MAIN_MENU );
5258 // All code to process events. This is the only place
5259 // that you should change the state of the game.
5260 void game_process_event( int current_state, int event )
5262 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5265 case GS_EVENT_SIMULATOR_ROOM:
5266 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5269 case GS_EVENT_MAIN_MENU:
5270 gameseq_set_state(GS_STATE_MAIN_MENU);
5273 case GS_EVENT_OPTIONS_MENU:
5274 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5277 case GS_EVENT_BARRACKS_MENU:
5278 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5281 case GS_EVENT_TECH_MENU:
5282 gameseq_set_state(GS_STATE_TECH_MENU);
5285 case GS_EVENT_TRAINING_MENU:
5286 gameseq_set_state(GS_STATE_TRAINING_MENU);
5289 case GS_EVENT_START_GAME:
5290 Select_default_ship = 0;
5291 Player_multi_died_check = -1;
5292 gameseq_set_state(GS_STATE_CMD_BRIEF);
5295 case GS_EVENT_START_BRIEFING:
5296 gameseq_set_state(GS_STATE_BRIEFING);
5299 case GS_EVENT_DEBRIEF:
5300 // did we end the campaign in the main freespace 2 single player campaign?
5302 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace")) {
5304 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5306 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5308 gameseq_set_state(GS_STATE_DEBRIEF);
5311 Player_multi_died_check = -1;
5314 case GS_EVENT_SHIP_SELECTION:
5315 gameseq_set_state( GS_STATE_SHIP_SELECT );
5318 case GS_EVENT_WEAPON_SELECTION:
5319 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5322 case GS_EVENT_ENTER_GAME:
5324 // maybe start recording a demo
5326 demo_start_record("test.fsd");
5330 if (Game_mode & GM_MULTIPLAYER) {
5331 // if we're respawning, make sure we change the view mode so that the hud shows up
5332 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5336 gameseq_set_state(GS_STATE_GAME_PLAY);
5338 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5341 Player_multi_died_check = -1;
5343 // clear multiplayer button info
5344 extern button_info Multi_ship_status_bi;
5345 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5347 Start_time = f2fl(timer_get_approx_seconds());
5349 mprintf(("Entering game at time = %7.3f\n", Start_time));
5353 case GS_EVENT_START_GAME_QUICK:
5354 Select_default_ship = 1;
5355 gameseq_post_event(GS_EVENT_ENTER_GAME);
5359 case GS_EVENT_END_GAME:
5360 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5361 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5362 gameseq_set_state(GS_STATE_MAIN_MENU);
5367 Player_multi_died_check = -1;
5370 case GS_EVENT_QUIT_GAME:
5371 main_hall_stop_music();
5372 main_hall_stop_ambient();
5373 gameseq_set_state(GS_STATE_QUIT_GAME);
5375 Player_multi_died_check = -1;
5378 case GS_EVENT_GAMEPLAY_HELP:
5379 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5382 case GS_EVENT_PAUSE_GAME:
5383 gameseq_push_state(GS_STATE_GAME_PAUSED);
5386 case GS_EVENT_DEBUG_PAUSE_GAME:
5387 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5390 case GS_EVENT_TRAINING_PAUSE:
5391 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5394 case GS_EVENT_PREVIOUS_STATE:
5395 gameseq_pop_state();
5398 case GS_EVENT_TOGGLE_FULLSCREEN:
5399 #ifndef HARDWARE_ONLY
5401 if ( gr_screen.mode == GR_SOFTWARE ) {
5402 gr_init( GR_640, GR_DIRECTDRAW );
5403 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5404 gr_init( GR_640, GR_SOFTWARE );
5410 case GS_EVENT_TOGGLE_GLIDE:
5412 if ( gr_screen.mode != GR_GLIDE ) {
5413 gr_init( GR_640, GR_GLIDE );
5415 gr_init( GR_640, GR_SOFTWARE );
5420 case GS_EVENT_LOAD_MISSION_MENU:
5421 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5424 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5425 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5428 case GS_EVENT_HUD_CONFIG:
5429 gameseq_push_state( GS_STATE_HUD_CONFIG );
5432 case GS_EVENT_CONTROL_CONFIG:
5433 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5436 case GS_EVENT_DEATH_DIED:
5437 gameseq_set_state( GS_STATE_DEATH_DIED );
5440 case GS_EVENT_DEATH_BLEW_UP:
5441 if ( current_state == GS_STATE_DEATH_DIED ) {
5442 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5443 event_music_player_death();
5445 // multiplayer clients set their extra check here
5446 if(Game_mode & GM_MULTIPLAYER){
5447 // set the multi died absolute last chance check
5448 Player_multi_died_check = time(NULL);
5451 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5455 case GS_EVENT_NEW_CAMPAIGN:
5456 if (!mission_load_up_campaign()){
5457 readyroom_continue_campaign();
5460 Player_multi_died_check = -1;
5463 case GS_EVENT_CAMPAIGN_CHEAT:
5464 if (!mission_load_up_campaign()){
5466 // bash campaign value
5467 extern char Main_hall_campaign_cheat[512];
5470 // look for the mission
5471 for(idx=0; idx<Campaign.num_missions; idx++){
5472 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5473 Campaign.next_mission = idx;
5474 Campaign.prev_mission = idx - 1;
5481 readyroom_continue_campaign();
5484 Player_multi_died_check = -1;
5487 case GS_EVENT_CAMPAIGN_ROOM:
5488 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5491 case GS_EVENT_CMD_BRIEF:
5492 gameseq_set_state(GS_STATE_CMD_BRIEF);
5495 case GS_EVENT_RED_ALERT:
5496 gameseq_set_state(GS_STATE_RED_ALERT);
5499 case GS_EVENT_CREDITS:
5500 gameseq_set_state( GS_STATE_CREDITS );
5503 case GS_EVENT_VIEW_MEDALS:
5504 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5507 case GS_EVENT_SHOW_GOALS:
5508 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5511 case GS_EVENT_HOTKEY_SCREEN:
5512 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5515 // multiplayer stuff follow these comments
5517 case GS_EVENT_MULTI_JOIN_GAME:
5518 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5521 case GS_EVENT_MULTI_HOST_SETUP:
5522 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5525 case GS_EVENT_MULTI_CLIENT_SETUP:
5526 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5529 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5530 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5533 case GS_EVENT_MULTI_STD_WAIT:
5534 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5537 case GS_EVENT_STANDALONE_MAIN:
5538 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5541 case GS_EVENT_MULTI_PAUSE:
5542 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5545 case GS_EVENT_INGAME_PRE_JOIN:
5546 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5549 case GS_EVENT_EVENT_DEBUG:
5550 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5553 // Start a warpout where player automatically goes 70 no matter what
5554 // and can't cancel out of it.
5555 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5556 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5558 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5559 Player->saved_viewer_mode = Viewer_mode;
5560 Player->control_mode = PCM_WARPOUT_STAGE1;
5561 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5562 Warpout_time = 0.0f; // Start timer!
5565 case GS_EVENT_PLAYER_WARPOUT_START:
5566 if ( Player->control_mode != PCM_NORMAL ) {
5567 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5569 Player->saved_viewer_mode = Viewer_mode;
5570 Player->control_mode = PCM_WARPOUT_STAGE1;
5571 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5572 Warpout_time = 0.0f; // Start timer!
5573 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5577 case GS_EVENT_PLAYER_WARPOUT_STOP:
5578 if ( Player->control_mode != PCM_NORMAL ) {
5579 if ( !Warpout_forced ) { // cannot cancel forced warpout
5580 Player->control_mode = PCM_NORMAL;
5581 Viewer_mode = Player->saved_viewer_mode;
5582 hud_subspace_notify_abort();
5583 mprintf(( "Player put back to normal mode.\n" ));
5584 if ( Warpout_sound > -1 ) {
5585 snd_stop( Warpout_sound );
5592 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5593 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5594 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5595 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5597 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5598 shipfx_warpout_start( Player_obj );
5599 Player->control_mode = PCM_WARPOUT_STAGE2;
5600 Player->saved_viewer_mode = Viewer_mode;
5601 Viewer_mode |= VM_WARP_CHASE;
5603 vector tmp = Player_obj->pos;
5605 ship_get_eye( &tmp, &tmp_m, Player_obj );
5606 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5607 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5608 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5610 camera_set_position( &tmp );
5611 camera_set_orient( &Player_obj->orient );
5612 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5614 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5615 camera_set_velocity( &tmp_vel, 1);
5619 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5620 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5621 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5622 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5624 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5625 Player->control_mode = PCM_WARPOUT_STAGE3;
5629 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5630 mprintf(( "Player warped out. Going to debriefing!\n" ));
5631 Player->control_mode = PCM_NORMAL;
5632 Viewer_mode = Player->saved_viewer_mode;
5635 // we have a special debriefing screen for multiplayer furballs
5636 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5637 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5639 // do the normal debriefing for all other situations
5641 gameseq_post_event(GS_EVENT_DEBRIEF);
5645 case GS_EVENT_STANDALONE_POSTGAME:
5646 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5649 case GS_EVENT_INITIAL_PLAYER_SELECT:
5650 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5653 case GS_EVENT_GAME_INIT:
5654 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5655 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5657 // see if the command line option has been set to use the last pilot, and act acoordingly
5658 if( player_select_get_last_pilot() ) {
5659 // always enter the main menu -- do the automatic network startup stuff elsewhere
5660 // so that we still have valid checks for networking modes, etc.
5661 gameseq_set_state(GS_STATE_MAIN_MENU);
5663 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5668 case GS_EVENT_MULTI_MISSION_SYNC:
5669 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5672 case GS_EVENT_MULTI_START_GAME:
5673 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5676 case GS_EVENT_MULTI_HOST_OPTIONS:
5677 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5680 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5681 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5684 case GS_EVENT_TEAM_SELECT:
5685 gameseq_set_state(GS_STATE_TEAM_SELECT);
5688 case GS_EVENT_END_CAMPAIGN:
5689 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5692 case GS_EVENT_END_DEMO:
5693 gameseq_set_state(GS_STATE_END_DEMO);
5696 case GS_EVENT_LOOP_BRIEF:
5697 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5706 // Called when a state is being left.
5707 // The current state is still at old_state, but as soon as
5708 // this function leaves, then the current state will become
5709 // new state. You should never try to change the state
5710 // in here... if you think you need to, you probably really
5711 // need to post an event, not change the state.
5712 void game_leave_state( int old_state, int new_state )
5714 int end_mission = 1;
5716 switch (new_state) {
5717 case GS_STATE_GAME_PAUSED:
5718 case GS_STATE_DEBUG_PAUSED:
5719 case GS_STATE_OPTIONS_MENU:
5720 case GS_STATE_CONTROL_CONFIG:
5721 case GS_STATE_MISSION_LOG_SCROLLBACK:
5722 case GS_STATE_DEATH_DIED:
5723 case GS_STATE_SHOW_GOALS:
5724 case GS_STATE_HOTKEY_SCREEN:
5725 case GS_STATE_MULTI_PAUSED:
5726 case GS_STATE_TRAINING_PAUSED:
5727 case GS_STATE_EVENT_DEBUG:
5728 case GS_STATE_GAMEPLAY_HELP:
5729 end_mission = 0; // these events shouldn't end a mission
5733 switch (old_state) {
5734 case GS_STATE_BRIEFING:
5735 brief_stop_voices();
5736 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5737 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5738 && (new_state != GS_STATE_TEAM_SELECT) ){
5739 common_select_close();
5740 if ( new_state == GS_STATE_MAIN_MENU ) {
5741 freespace_stop_mission();
5745 // COMMAND LINE OPTION
5746 if (Cmdline_multi_stream_chat_to_file){
5747 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5748 cfclose(Multi_chat_stream);
5752 case GS_STATE_DEBRIEF:
5753 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5758 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5759 multi_df_debrief_close();
5762 case GS_STATE_LOAD_MISSION_MENU:
5763 mission_load_menu_close();
5766 case GS_STATE_SIMULATOR_ROOM:
5770 case GS_STATE_CAMPAIGN_ROOM:
5771 campaign_room_close();
5774 case GS_STATE_CMD_BRIEF:
5775 if (new_state == GS_STATE_OPTIONS_MENU) {
5780 if (new_state == GS_STATE_MAIN_MENU)
5781 freespace_stop_mission();
5786 case GS_STATE_RED_ALERT:
5790 case GS_STATE_SHIP_SELECT:
5791 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5792 new_state != GS_STATE_HOTKEY_SCREEN &&
5793 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5794 common_select_close();
5795 if ( new_state == GS_STATE_MAIN_MENU ) {
5796 freespace_stop_mission();
5801 case GS_STATE_WEAPON_SELECT:
5802 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5803 new_state != GS_STATE_HOTKEY_SCREEN &&
5804 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5805 common_select_close();
5806 if ( new_state == GS_STATE_MAIN_MENU ) {
5807 freespace_stop_mission();
5812 case GS_STATE_TEAM_SELECT:
5813 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5814 new_state != GS_STATE_HOTKEY_SCREEN &&
5815 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5816 common_select_close();
5817 if ( new_state == GS_STATE_MAIN_MENU ) {
5818 freespace_stop_mission();
5823 case GS_STATE_MAIN_MENU:
5824 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5831 case GS_STATE_OPTIONS_MENU:
5832 //game_start_time();
5833 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5834 multi_join_clear_game_list();
5836 options_menu_close();
5839 case GS_STATE_BARRACKS_MENU:
5840 if(new_state != GS_STATE_VIEW_MEDALS){
5845 case GS_STATE_MISSION_LOG_SCROLLBACK:
5846 hud_scrollback_close();
5849 case GS_STATE_TRAINING_MENU:
5850 training_menu_close();
5853 case GS_STATE_GAME_PLAY:
5854 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5855 player_save_target_and_weapon_link_prefs();
5856 game_stop_looped_sounds();
5859 sound_env_disable();
5860 joy_ff_stop_effects();
5862 // stop game time under certain conditions
5863 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5868 // shut down any recording or playing demos
5873 // when in multiplayer and going back to the main menu, send a leave game packet
5874 // right away (before calling stop mission). stop_mission was taking to long to
5875 // close mission down and I want people to get notified ASAP.
5876 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5877 multi_quit_game(PROMPT_NONE);
5880 freespace_stop_mission();
5881 Game_time_compression = F1_0;
5885 case GS_STATE_TECH_MENU:
5889 case GS_STATE_TRAINING_PAUSED:
5890 Training_num_lines = 0;
5891 // fall through to GS_STATE_GAME_PAUSED
5893 case GS_STATE_GAME_PAUSED:
5895 if ( end_mission ) {
5900 case GS_STATE_DEBUG_PAUSED:
5903 pause_debug_close();
5907 case GS_STATE_HUD_CONFIG:
5911 // join/start a game
5912 case GS_STATE_MULTI_JOIN_GAME:
5913 if(new_state != GS_STATE_OPTIONS_MENU){
5914 multi_join_game_close();
5918 case GS_STATE_MULTI_HOST_SETUP:
5919 case GS_STATE_MULTI_CLIENT_SETUP:
5920 // if this is just the host going into the options screen, don't do anything
5921 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5925 // close down the proper state
5926 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5927 multi_create_game_close();
5929 multi_game_client_setup_close();
5932 // COMMAND LINE OPTION
5933 if (Cmdline_multi_stream_chat_to_file){
5934 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5935 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5936 cfclose(Multi_chat_stream);
5941 case GS_STATE_CONTROL_CONFIG:
5942 control_config_close();
5945 case GS_STATE_DEATH_DIED:
5946 Game_mode &= ~GM_DEAD_DIED;
5948 // early end while respawning or blowing up in a multiplayer game
5949 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5951 freespace_stop_mission();
5955 case GS_STATE_DEATH_BLEW_UP:
5956 Game_mode &= ~GM_DEAD_BLEW_UP;
5958 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5959 // to determine if I should do anything.
5960 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5962 freespace_stop_mission();
5965 // if we are not respawing as an observer or as a player, our new state will not
5966 // be gameplay state.
5967 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5968 game_stop_time(); // hasn't been called yet!!
5969 freespace_stop_mission();
5975 case GS_STATE_CREDITS:
5979 case GS_STATE_VIEW_MEDALS:
5983 case GS_STATE_SHOW_GOALS:
5984 mission_show_goals_close();
5987 case GS_STATE_HOTKEY_SCREEN:
5988 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5989 mission_hotkey_close();
5993 case GS_STATE_MULTI_MISSION_SYNC:
5994 // if we're moving into the options menu, don't do anything
5995 if(new_state == GS_STATE_OPTIONS_MENU){
5999 Assert( Game_mode & GM_MULTIPLAYER );
6001 if ( new_state == GS_STATE_GAME_PLAY ){
6002 // palette_restore_palette();
6004 // change a couple of flags to indicate our state!!!
6005 Net_player->state = NETPLAYER_STATE_IN_MISSION;
6006 send_netplayer_update_packet();
6008 // set the game mode
6009 Game_mode |= GM_IN_MISSION;
6013 case GS_STATE_VIEW_CUTSCENES:
6014 cutscenes_screen_close();
6017 case GS_STATE_MULTI_STD_WAIT:
6018 multi_standalone_wait_close();
6021 case GS_STATE_STANDALONE_MAIN:
6022 standalone_main_close();
6023 if(new_state == GS_STATE_MULTI_STD_WAIT){
6024 init_multiplayer_stats();
6028 case GS_STATE_MULTI_PAUSED:
6029 // if ( end_mission ){
6034 case GS_STATE_INGAME_PRE_JOIN:
6035 multi_ingame_select_close();
6038 case GS_STATE_STANDALONE_POSTGAME:
6039 multi_standalone_postgame_close();
6042 case GS_STATE_INITIAL_PLAYER_SELECT:
6043 player_select_close();
6046 case GS_STATE_MULTI_START_GAME:
6047 multi_start_game_close();
6050 case GS_STATE_MULTI_HOST_OPTIONS:
6051 multi_host_options_close();
6054 case GS_STATE_END_OF_CAMPAIGN:
6055 mission_campaign_end_close();
6058 case GS_STATE_LOOP_BRIEF:
6064 // Called when a state is being entered.
6065 // The current state is set to the state we're entering at
6066 // this point, and old_state is set to the state we're coming
6067 // from. You should never try to change the state
6068 // in here... if you think you need to, you probably really
6069 // need to post an event, not change the state.
6071 void game_enter_state( int old_state, int new_state )
6073 switch (new_state) {
6074 case GS_STATE_MAIN_MENU:
6075 // in multiplayer mode, be sure that we are not doing networking anymore.
6076 if ( Game_mode & GM_MULTIPLAYER ) {
6077 Assert( Net_player != NULL );
6078 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
6081 Game_time_compression = F1_0;
6083 // determine which ship this guy is currently based on
6084 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6087 if (Player->on_bastion) {
6095 case GS_STATE_BRIEFING:
6096 main_hall_stop_music();
6097 main_hall_stop_ambient();
6099 if (Game_mode & GM_NORMAL) {
6100 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6101 // MWA: or from options or hotkey screens
6102 // JH: or if the command brief state already did this
6103 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6104 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
6105 && (old_state != GS_STATE_CMD_BRIEF) ) {
6106 if ( !game_start_mission() ) // this should put us into a new state on failure!
6110 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6111 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6112 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6114 Game_time_compression = F1_0;
6116 if ( red_alert_mission() ) {
6117 gameseq_post_event(GS_EVENT_RED_ALERT);
6124 case GS_STATE_DEBRIEF:
6125 game_stop_looped_sounds();
6126 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
6127 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
6132 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6133 multi_df_debrief_init();
6136 case GS_STATE_LOAD_MISSION_MENU:
6137 mission_load_menu_init();
6140 case GS_STATE_SIMULATOR_ROOM:
6144 case GS_STATE_CAMPAIGN_ROOM:
6145 campaign_room_init();
6148 case GS_STATE_RED_ALERT:
6149 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6153 case GS_STATE_CMD_BRIEF: {
6154 int team_num = 0; // team number used as index for which cmd brief to use.
6156 if (old_state == GS_STATE_OPTIONS_MENU) {
6160 main_hall_stop_music();
6161 main_hall_stop_ambient();
6163 if (Game_mode & GM_NORMAL) {
6164 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6165 // MWA: or from options or hotkey screens
6166 // JH: or if the command brief state already did this
6167 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6168 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
6169 if ( !game_start_mission() ) // this should put us into a new state on failure!
6174 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6175 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6176 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6178 cmd_brief_init(team_num);
6184 case GS_STATE_SHIP_SELECT:
6188 case GS_STATE_WEAPON_SELECT:
6189 weapon_select_init();
6192 case GS_STATE_TEAM_SELECT:
6196 case GS_STATE_GAME_PAUSED:
6201 case GS_STATE_DEBUG_PAUSED:
6202 // game_stop_time();
6203 // os_set_title("FreeSpace - PAUSED");
6206 case GS_STATE_TRAINING_PAUSED:
6213 case GS_STATE_OPTIONS_MENU:
6215 options_menu_init();
6218 case GS_STATE_GAME_PLAY:
6219 // coming from the gameplay state or the main menu, we might need to load the mission
6220 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
6221 if ( !game_start_mission() ) // this should put us into a new state.
6226 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
6227 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
6228 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
6229 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
6230 (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) ) {
6231 // JAS: Used to do all paging here.
6235 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
6239 main_hall_stop_music();
6240 main_hall_stop_ambient();
6241 event_music_first_pattern(); // start the first pattern
6244 // special code that restores player ship selection and weapons loadout when doing a quick start
6245 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
6246 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
6247 wss_direct_restore_loadout();
6251 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
6252 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
6253 event_music_first_pattern(); // start the first pattern
6256 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
6257 event_music_first_pattern(); // start the first pattern
6259 player_restore_target_and_weapon_link_prefs();
6261 Game_mode |= GM_IN_MISSION;
6264 // required to truely make mouse deltas zeroed in debug mouse code
6265 void mouse_force_pos(int x, int y);
6266 if (!Is_standalone) {
6267 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6273 // only start time if in single player, or coming from multi wait state
6276 (Game_mode & GM_NORMAL) &&
6277 (old_state != GS_STATE_VIEW_CUTSCENES)
6279 (Game_mode & GM_MULTIPLAYER) && (
6280 (old_state == GS_STATE_MULTI_PAUSED) ||
6281 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6287 // when coming from the multi paused state, reset the timestamps
6288 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6289 multi_reset_timestamps();
6292 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6293 // initialize all object update details
6294 multi_oo_gameplay_init();
6297 // under certain circumstances, the server should reset the object update rate limiting stuff
6298 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6299 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6301 // reinitialize the rate limiting system for all clients
6302 multi_oo_rate_init_all();
6305 // multiplayer clients should always re-initialize their control info rate limiting system
6306 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6307 multi_oo_rate_init_all();
6311 if(Game_mode & GM_MULTIPLAYER){
6312 multi_ping_reset_players();
6315 Game_subspace_effect = 0;
6316 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6317 Game_subspace_effect = 1;
6318 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6319 game_start_subspace_ambient_sound();
6323 sound_env_set(&Game_sound_env);
6324 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6326 // clear multiplayer button info i
6327 extern button_info Multi_ship_status_bi;
6328 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6331 case GS_STATE_HUD_CONFIG:
6335 case GS_STATE_MULTI_JOIN_GAME:
6336 multi_join_clear_game_list();
6338 if (old_state != GS_STATE_OPTIONS_MENU) {
6339 multi_join_game_init();
6344 case GS_STATE_MULTI_HOST_SETUP:
6345 // don't reinitialize if we're coming back from the host options screen
6346 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6347 multi_create_game_init();
6352 case GS_STATE_MULTI_CLIENT_SETUP:
6353 if (old_state != GS_STATE_OPTIONS_MENU) {
6354 multi_game_client_setup_init();
6359 case GS_STATE_CONTROL_CONFIG:
6360 control_config_init();
6363 case GS_STATE_TECH_MENU:
6367 case GS_STATE_BARRACKS_MENU:
6368 if(old_state != GS_STATE_VIEW_MEDALS){
6373 case GS_STATE_MISSION_LOG_SCROLLBACK:
6374 hud_scrollback_init();
6377 case GS_STATE_DEATH_DIED:
6378 Player_died_time = timestamp(10);
6380 if(!(Game_mode & GM_MULTIPLAYER)){
6381 player_show_death_message();
6383 Game_mode |= GM_DEAD_DIED;
6386 case GS_STATE_DEATH_BLEW_UP:
6387 if ( !popupdead_is_active() ) {
6388 Player_ai->target_objnum = -1;
6391 // stop any local EMP effect
6394 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6395 Game_mode |= GM_DEAD_BLEW_UP;
6396 Show_viewing_from_self = 0;
6398 // timestamp how long we should wait before displaying the died popup
6399 if ( !popupdead_is_active() ) {
6400 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6404 case GS_STATE_GAMEPLAY_HELP:
6405 gameplay_help_init();
6408 case GS_STATE_CREDITS:
6409 main_hall_stop_music();
6410 main_hall_stop_ambient();
6414 case GS_STATE_VIEW_MEDALS:
6415 medal_main_init(Player);
6418 case GS_STATE_SHOW_GOALS:
6419 mission_show_goals_init();
6422 case GS_STATE_HOTKEY_SCREEN:
6423 mission_hotkey_init();
6426 case GS_STATE_MULTI_MISSION_SYNC:
6427 // if we're coming from the options screen, don't do any
6428 if(old_state == GS_STATE_OPTIONS_MENU){
6432 switch(Multi_sync_mode){
6433 case MULTI_SYNC_PRE_BRIEFING:
6434 // if moving from game forming to the team select state
6437 case MULTI_SYNC_POST_BRIEFING:
6438 // if moving from briefing into the mission itself
6441 // tell everyone that we're now loading data
6442 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6443 send_netplayer_update_packet();
6445 // JAS: Used to do all paging here!!!!
6447 Net_player->state = NETPLAYER_STATE_WAITING;
6448 send_netplayer_update_packet();
6450 Game_time_compression = F1_0;
6452 case MULTI_SYNC_INGAME:
6458 case GS_STATE_VIEW_CUTSCENES:
6459 cutscenes_screen_init();
6462 case GS_STATE_MULTI_STD_WAIT:
6463 multi_standalone_wait_init();
6466 case GS_STATE_STANDALONE_MAIN:
6467 // don't initialize if we're coming from one of these 2 states unless there are no
6468 // players left (reset situation)
6469 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6470 standalone_main_init();
6474 case GS_STATE_MULTI_PAUSED:
6478 case GS_STATE_INGAME_PRE_JOIN:
6479 multi_ingame_select_init();
6482 case GS_STATE_STANDALONE_POSTGAME:
6483 multi_standalone_postgame_init();
6486 case GS_STATE_INITIAL_PLAYER_SELECT:
6487 player_select_init();
6490 case GS_STATE_MULTI_START_GAME:
6491 multi_start_game_init();
6494 case GS_STATE_MULTI_HOST_OPTIONS:
6495 multi_host_options_init();
6498 case GS_STATE_END_OF_CAMPAIGN:
6499 mission_campaign_end_init();
6502 case GS_STATE_LOOP_BRIEF:
6509 // do stuff that may need to be done regardless of state
6510 void game_do_state_common(int state,int no_networking)
6512 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6513 snd_do_frame(); // update sound system
6514 event_music_do_frame(); // music needs to play across many states
6516 multi_log_process();
6518 if (no_networking) {
6522 // maybe do a multiplayer frame based on game mode and state type
6523 if (Game_mode & GM_MULTIPLAYER) {
6525 case GS_STATE_OPTIONS_MENU:
6526 case GS_STATE_GAMEPLAY_HELP:
6527 case GS_STATE_HOTKEY_SCREEN:
6528 case GS_STATE_HUD_CONFIG:
6529 case GS_STATE_CONTROL_CONFIG:
6530 case GS_STATE_MISSION_LOG_SCROLLBACK:
6531 case GS_STATE_SHOW_GOALS:
6532 case GS_STATE_VIEW_CUTSCENES:
6533 case GS_STATE_EVENT_DEBUG:
6534 multi_maybe_do_frame();
6538 game_do_networking();
6542 // Called once a frame.
6543 // You should never try to change the state
6544 // in here... if you think you need to, you probably really
6545 // need to post an event, not change the state.
6546 int Game_do_state_should_skip = 0;
6547 void game_do_state(int state)
6549 // always lets the do_state_common() function determine if the state should be skipped
6550 Game_do_state_should_skip = 0;
6552 // legal to set the should skip state anywhere in this function
6553 game_do_state_common(state); // do stuff that may need to be done regardless of state
6555 if(Game_do_state_should_skip){
6560 case GS_STATE_MAIN_MENU:
6561 game_set_frametime(GS_STATE_MAIN_MENU);
6562 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6565 main_hall_do(flFrametime);
6569 case GS_STATE_OPTIONS_MENU:
6570 game_set_frametime(GS_STATE_OPTIONS_MENU);
6571 options_menu_do_frame(flFrametime);
6574 case GS_STATE_BARRACKS_MENU:
6575 game_set_frametime(GS_STATE_BARRACKS_MENU);
6576 barracks_do_frame(flFrametime);
6579 case GS_STATE_TRAINING_MENU:
6580 game_set_frametime(GS_STATE_TRAINING_MENU);
6581 training_menu_do_frame(flFrametime);
6584 case GS_STATE_TECH_MENU:
6585 game_set_frametime(GS_STATE_TECH_MENU);
6586 techroom_do_frame(flFrametime);
6589 case GS_STATE_GAMEPLAY_HELP:
6590 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6591 gameplay_help_do_frame(flFrametime);
6594 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6598 case GS_STATE_GAME_PAUSED:
6602 case GS_STATE_DEBUG_PAUSED:
6604 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6609 case GS_STATE_TRAINING_PAUSED:
6610 game_training_pause_do();
6613 case GS_STATE_LOAD_MISSION_MENU:
6614 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6615 mission_load_menu_do();
6618 case GS_STATE_BRIEFING:
6619 game_set_frametime(GS_STATE_BRIEFING);
6620 brief_do_frame(flFrametime);
6623 case GS_STATE_DEBRIEF:
6624 game_set_frametime(GS_STATE_DEBRIEF);
6625 debrief_do_frame(flFrametime);
6628 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6629 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6630 multi_df_debrief_do();
6633 case GS_STATE_SHIP_SELECT:
6634 game_set_frametime(GS_STATE_SHIP_SELECT);
6635 ship_select_do(flFrametime);
6638 case GS_STATE_WEAPON_SELECT:
6639 game_set_frametime(GS_STATE_WEAPON_SELECT);
6640 weapon_select_do(flFrametime);
6643 case GS_STATE_MISSION_LOG_SCROLLBACK:
6644 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6645 hud_scrollback_do_frame(flFrametime);
6648 case GS_STATE_HUD_CONFIG:
6649 game_set_frametime(GS_STATE_HUD_CONFIG);
6650 hud_config_do_frame(flFrametime);
6653 case GS_STATE_MULTI_JOIN_GAME:
6654 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6655 multi_join_game_do_frame();
6658 case GS_STATE_MULTI_HOST_SETUP:
6659 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6660 multi_create_game_do();
6663 case GS_STATE_MULTI_CLIENT_SETUP:
6664 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6665 multi_game_client_setup_do_frame();
6668 case GS_STATE_CONTROL_CONFIG:
6669 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6670 control_config_do_frame(flFrametime);
6673 case GS_STATE_DEATH_DIED:
6677 case GS_STATE_DEATH_BLEW_UP:
6681 case GS_STATE_SIMULATOR_ROOM:
6682 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6683 sim_room_do_frame(flFrametime);
6686 case GS_STATE_CAMPAIGN_ROOM:
6687 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6688 campaign_room_do_frame(flFrametime);
6691 case GS_STATE_RED_ALERT:
6692 game_set_frametime(GS_STATE_RED_ALERT);
6693 red_alert_do_frame(flFrametime);
6696 case GS_STATE_CMD_BRIEF:
6697 game_set_frametime(GS_STATE_CMD_BRIEF);
6698 cmd_brief_do_frame(flFrametime);
6701 case GS_STATE_CREDITS:
6702 game_set_frametime(GS_STATE_CREDITS);
6703 credits_do_frame(flFrametime);
6706 case GS_STATE_VIEW_MEDALS:
6707 game_set_frametime(GS_STATE_VIEW_MEDALS);
6711 case GS_STATE_SHOW_GOALS:
6712 game_set_frametime(GS_STATE_SHOW_GOALS);
6713 mission_show_goals_do_frame(flFrametime);
6716 case GS_STATE_HOTKEY_SCREEN:
6717 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6718 mission_hotkey_do_frame(flFrametime);
6721 case GS_STATE_VIEW_CUTSCENES:
6722 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6723 cutscenes_screen_do_frame();
6726 case GS_STATE_MULTI_STD_WAIT:
6727 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6728 multi_standalone_wait_do();
6731 case GS_STATE_STANDALONE_MAIN:
6732 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6733 standalone_main_do();
6736 case GS_STATE_MULTI_PAUSED:
6737 game_set_frametime(GS_STATE_MULTI_PAUSED);
6741 case GS_STATE_TEAM_SELECT:
6742 game_set_frametime(GS_STATE_TEAM_SELECT);
6746 case GS_STATE_INGAME_PRE_JOIN:
6747 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6748 multi_ingame_select_do();
6751 case GS_STATE_EVENT_DEBUG:
6753 game_set_frametime(GS_STATE_EVENT_DEBUG);
6754 game_show_event_debug(flFrametime);
6758 case GS_STATE_STANDALONE_POSTGAME:
6759 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6760 multi_standalone_postgame_do();
6763 case GS_STATE_INITIAL_PLAYER_SELECT:
6764 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6768 case GS_STATE_MULTI_MISSION_SYNC:
6769 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6773 case GS_STATE_MULTI_START_GAME:
6774 game_set_frametime(GS_STATE_MULTI_START_GAME);
6775 multi_start_game_do();
6778 case GS_STATE_MULTI_HOST_OPTIONS:
6779 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6780 multi_host_options_do();
6783 case GS_STATE_END_OF_CAMPAIGN:
6784 mission_campaign_end_do();
6787 case GS_STATE_END_DEMO:
6788 game_set_frametime(GS_STATE_END_DEMO);
6789 end_demo_campaign_do();
6792 case GS_STATE_LOOP_BRIEF:
6793 game_set_frametime(GS_STATE_LOOP_BRIEF);
6797 } // end switch(gs_current_state)
6801 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6802 int game_do_ram_check(int ram_in_bytes)
6804 if ( ram_in_bytes < 30*1024*1024 ) {
6805 int allowed_to_run = 1;
6806 if ( ram_in_bytes < 25*1024*1024 ) {
6811 int Freespace_total_ram_MB;
6812 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6814 if ( allowed_to_run ) {
6816 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), Freespace_total_ram_MB, Freespace_total_ram_MB);
6821 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6822 if ( msgbox_rval == IDCANCEL ) {
6829 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), Freespace_total_ram_MB, Freespace_total_ram_MB);
6831 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6842 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6843 // If so, copy it over and remove the update directory.
6844 void game_maybe_update_launcher(char *exe_dir)
6847 char src_filename[MAX_PATH];
6848 char dest_filename[MAX_PATH];
6850 strcpy(src_filename, exe_dir);
6851 strcat(src_filename, NOX("\\update\\freespace.exe"));
6853 strcpy(dest_filename, exe_dir);
6854 strcat(dest_filename, NOX("\\freespace.exe"));
6856 // see if src_filename exists
6858 fp = fopen(src_filename, "rb");
6864 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6866 // copy updated freespace.exe to freespace exe dir
6867 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6868 MessageBox( NULL, XSTR("Unable to copy freespace.exe from update directory to installed directory. You should copy freespace.exe from the update directory (located in your FreeSpace install directory) to your install directory", 988), NULL, MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
6872 // delete the file in the update directory
6873 DeleteFile(src_filename);
6875 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6876 char update_dir[MAX_PATH];
6877 strcpy(update_dir, exe_dir);
6878 strcat(update_dir, NOX("\\update"));
6879 RemoveDirectory(update_dir);
6885 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6889 int sub_total_destroyed = 0;
6893 // get the total for all his children
6894 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6895 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6898 // find the # of faces for this _individual_ object
6899 total = submodel_get_num_polys(model_num, sm);
6900 if(strstr(pm->submodel[sm].name, "-destroyed")){
6901 sub_total_destroyed = total;
6905 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6908 *out_total += total + sub_total;
6909 *out_destroyed_total += sub_total_destroyed;
6912 #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);
6913 void game_spew_pof_info()
6915 char *pof_list[1000];
6918 int idx, model_num, i, j;
6920 int total, root_total, model_total, destroyed_total, counted;
6924 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6926 // spew info on all the pofs
6932 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6937 for(idx=0; idx<num_files; idx++, counted++){
6938 sprintf(str, "%s.pof", pof_list[idx]);
6939 model_num = model_load(str, 0, NULL);
6941 pm = model_get(model_num);
6943 // if we have a real model
6948 // go through and print all raw submodels
6949 cfputs("RAW\n", out);
6952 for (i=0; i<pm->n_models; i++) {
6953 total = submodel_get_num_polys(model_num, i);
6955 model_total += total;
6956 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6959 sprintf(str, "Model total %d\n", model_total);
6962 // now go through and do it by LOD
6963 cfputs("BY LOD\n\n", out);
6964 for(i=0; i<pm->n_detail_levels; i++){
6965 sprintf(str, "LOD %d\n", i);
6969 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6971 destroyed_total = 0;
6972 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6973 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6976 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6979 sprintf(str, "TOTAL: %d\n", total + root_total);
6981 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6983 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6986 cfputs("------------------------------------------------------------------------\n\n", out);
6990 if(counted >= MAX_POLYGON_MODELS - 5){
7003 game_spew_pof_info();
7006 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7011 // Don't let more than one instance of Freespace run.
7012 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
7014 SetForegroundWindow(hwnd);
7019 // Find out how much RAM is on this machine
7022 ms.dwLength = sizeof(MEMORYSTATUS);
7023 GlobalMemoryStatus(&ms);
7024 Freespace_total_ram = ms.dwTotalPhys;
7026 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
7030 if ( ms.dwTotalVirtual < 1024 ) {
7031 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
7035 if (!vm_init(24*1024*1024)) {
7036 MessageBox( NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK );
7040 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
7042 MessageBox(NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK);
7050 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
7051 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
7052 seem worth bothering with.
7056 lResult = RegOpenKeyEx(
7057 HKEY_LOCAL_MACHINE, // Where it is
7058 "Software\\Microsoft\\DirectX", // name of key
7059 NULL, // DWORD reserved
7060 KEY_QUERY_VALUE, // Allows all changes
7061 &hKey // Location to store key
7064 if (lResult == ERROR_SUCCESS) {
7066 DWORD dwType, dwLen;
7069 lResult = RegQueryValueEx(
7070 hKey, // Handle to key
7071 "Version", // The values name
7072 NULL, // DWORD reserved
7073 &dwType, // What kind it is
7074 (ubyte *) version, // value to set
7075 &dwLen // How many bytes to set
7078 if (lResult == ERROR_SUCCESS) {
7079 dx_version = atoi(strstr(version, ".") + 1);
7083 DWORD dwType, dwLen;
7086 lResult = RegQueryValueEx(
7087 hKey, // Handle to key
7088 "InstalledVersion", // The values name
7089 NULL, // DWORD reserved
7090 &dwType, // What kind it is
7091 (ubyte *) &val, // value to set
7092 &dwLen // How many bytes to set
7095 if (lResult == ERROR_SUCCESS) {
7103 if (dx_version < 3) {
7104 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
7105 "latest version of DirectX at:\n\n"
7106 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
7108 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
7109 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
7114 //=====================================================
7115 // Make sure we're running in the right directory.
7119 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
7120 char *p = exe_dir + strlen(exe_dir);
7122 // chop off the filename
7123 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
7129 if ( strlen(exe_dir) > 0 ) {
7130 SetCurrentDirectory(exe_dir);
7133 // check for updated freespace.exe
7134 game_maybe_update_launcher(exe_dir);
7142 extern void windebug_memwatch_init();
7143 windebug_memwatch_init();
7147 parse_cmdline(szCmdLine);
7149 #ifdef STANDALONE_ONLY_BUILD
7151 nprintf(("Network", "Standalone running"));
7154 nprintf(("Network", "Standalone running"));
7162 // maybe spew pof stuff
7163 if(Cmdline_spew_pof_info){
7164 game_spew_pof_info();
7169 // non-demo, non-standalone, play the intro movie
7175 // to avoid crashes on debug build
7176 for (i=0; i<5; i++) {
7180 if( (cf_get_file_list(2, plist, CF_TYPE_MULTI_PLAYERS, NOX("*.plr")) <= 0) && (cf_get_file_list(2, plist, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr")) <= 0) ){
7182 #if defined(OEM_BUILD)
7183 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
7185 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
7186 #endif // defined(OEM_BUILD)
7189 for (int i=0; i<5; i++) {
7190 if (plist[i] != NULL) {
7195 #endif // RELEASE_REAL
7198 if ( !Is_standalone ) {
7200 // release -- movies always play
7203 // 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
7204 movie_play( NOX("intro.mve"), 0 );
7206 // debug version, movie will only play with -showmovies
7207 #elif !defined(NDEBUG)
7209 movie_play( NOX("intro.mve"), 0);
7212 if ( Cmdline_show_movies )
7213 movie_play( NOX("intro.mve"), 0 );
7222 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
7224 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
7228 // only important for non THREADED mode
7231 state = gameseq_process_events();
7232 if ( state == GS_STATE_QUIT_GAME ){
7237 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7239 demo_upsell_show_screens();
7241 #elif defined(OEM_BUILD)
7242 // show upsell screens on exit
7243 oem_upsell_show_screens();
7250 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7256 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7258 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
7260 // Do nothing here - RecordExceptionInfo() has already done
7261 // everything that is needed. Actually this code won't even
7262 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
7263 // the __except clause.
7267 nprintf(("WinMain", "exceptions shall fall through"));
7269 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7275 // launcher the fslauncher program on exit
7276 void game_launch_launcher_on_exit()
7280 PROCESS_INFORMATION pi;
7281 char cmd_line[2048];
7282 char original_path[1024] = "";
7284 memset( &si, 0, sizeof(STARTUPINFO) );
7288 _getcwd(original_path, 1023);
7290 // set up command line
7291 strcpy(cmd_line, original_path);
7292 strcat(cmd_line, "\\");
7293 strcat(cmd_line, LAUNCHER_FNAME);
7294 strcat(cmd_line, " -straight_to_update");
7296 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7297 cmd_line, // pointer to command line string
7298 NULL, // pointer to process security attributes
7299 NULL, // pointer to thread security attributes
7300 FALSE, // handle inheritance flag
7301 CREATE_DEFAULT_ERROR_MODE, // creation flags
7302 NULL, // pointer to new environment block
7303 NULL, // pointer to current directory name
7304 &si, // pointer to STARTUPINFO
7305 &pi // pointer to PROCESS_INFORMATION
7307 // to eliminate build warnings
7317 // This function is called when FreeSpace terminates normally.
7319 void game_shutdown(void)
7325 // don't ever flip a page on the standalone!
7326 if(!(Game_mode & GM_STANDALONE_SERVER)){
7332 // if the player has left the "player select" screen and quit the game without actually choosing
7333 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7334 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7338 // load up common multiplayer icons
7339 multi_unload_common_icons();
7341 shockwave_close(); // release any memory used by shockwave system
7342 fireball_close(); // free fireball system
7343 ship_close(); // free any memory that was allocated for the ships
7344 weapon_close(); // free any memory that was allocated for the weapons
7345 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7346 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7347 bm_unload_all(); // free bitmaps
7348 mission_campaign_close(); // close out the campaign stuff
7349 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
7350 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7352 #ifdef MULTI_USE_LAG
7356 // the menu close functions will unload the bitmaps if they were displayed during the game
7357 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7360 context_help_close(); // close out help system
7361 training_menu_close();
7362 lcl_close(); // be sure localization is closed out
7365 // free left-over memory from parsed tables
7366 cutscene_tbl_close();
7368 scoring_tbl_close();
7369 player_tips_close();
7371 extern void joy_close();
7374 audiostream_close();
7376 event_music_close();
7380 // HACKITY HACK HACK
7381 // if this flag is set, we should be firing up the launcher when exiting freespace
7382 extern int Multi_update_fireup_launcher_on_exit;
7383 if(Multi_update_fireup_launcher_on_exit){
7384 game_launch_launcher_on_exit();
7388 // game_stop_looped_sounds()
7390 // This function will call the appropriate stop looped sound functions for those
7391 // modules which use looping sounds. It is not enough just to stop a looping sound
7392 // at the DirectSound level, the game is keeping track of looping sounds, and this
7393 // function is used to inform the game that looping sounds are being halted.
7395 void game_stop_looped_sounds()
7397 hud_stop_looped_locking_sounds();
7398 hud_stop_looped_engine_sounds();
7399 afterburner_stop_sounds();
7400 player_stop_looped_sounds();
7401 obj_snd_stop_all(); // stop all object-linked persistant sounds
7402 game_stop_subspace_ambient_sound();
7403 snd_stop(Radar_static_looping);
7404 Radar_static_looping = -1;
7405 snd_stop(Target_static_looping);
7406 shipfx_stop_engine_wash_sound();
7407 Target_static_looping = -1;
7410 //////////////////////////////////////////////////////////////////////////
7412 // Code for supporting an animating mouse pointer
7415 //////////////////////////////////////////////////////////////////////////
7417 typedef struct animating_obj
7426 static animating_obj Animating_mouse;
7428 // ----------------------------------------------------------------------------
7429 // init_animating_pointer()
7431 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7432 // gets properly initialized
7434 void init_animating_pointer()
7436 Animating_mouse.first_frame = -1;
7437 Animating_mouse.num_frames = 0;
7438 Animating_mouse.current_frame = -1;
7439 Animating_mouse.time = 0.0f;
7440 Animating_mouse.elapsed_time = 0.0f;
7443 // ----------------------------------------------------------------------------
7444 // load_animating_pointer()
7446 // Called at game init to load in the frames for the animating mouse pointer
7448 // input: filename => filename of animation file that holds the animation
7450 void load_animating_pointer(char *filename, int dx, int dy)
7455 init_animating_pointer();
7457 am = &Animating_mouse;
7458 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7459 if ( am->first_frame == -1 )
7460 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7461 am->current_frame = 0;
7462 am->time = am->num_frames / i2fl(fps);
7465 // ----------------------------------------------------------------------------
7466 // unload_animating_pointer()
7468 // Called at game shutdown to free the memory used to store the animation frames
7470 void unload_animating_pointer()
7475 am = &Animating_mouse;
7476 for ( i = 0; i < am->num_frames; i++ ) {
7477 Assert( (am->first_frame+i) >= 0 );
7478 bm_release(am->first_frame + i);
7481 am->first_frame = -1;
7483 am->current_frame = -1;
7486 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7487 void game_render_mouse(float frametime)
7492 // if animating cursor exists, play the next frame
7493 am = &Animating_mouse;
7494 if ( am->first_frame != -1 ) {
7495 mouse_get_pos(&mx, &my);
7496 am->elapsed_time += frametime;
7497 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7498 if ( am->current_frame >= am->num_frames ) {
7499 am->current_frame = 0;
7500 am->elapsed_time = 0.0f;
7502 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7506 // ----------------------------------------------------------------------------
7507 // game_maybe_draw_mouse()
7509 // determines whether to draw the mouse pointer at all, and what frame of
7510 // animation to use if the mouse is animating
7512 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7514 // input: frametime => elapsed frame time in seconds since last call
7516 void game_maybe_draw_mouse(float frametime)
7520 game_state = gameseq_get_state();
7522 switch ( game_state ) {
7523 case GS_STATE_GAME_PAUSED:
7524 // case GS_STATE_MULTI_PAUSED:
7525 case GS_STATE_GAME_PLAY:
7526 case GS_STATE_DEATH_DIED:
7527 case GS_STATE_DEATH_BLEW_UP:
7528 if ( popup_active() || popupdead_is_active() ) {
7540 if ( !Mouse_hidden )
7541 game_render_mouse(frametime);
7545 void game_do_training_checks()
7549 waypoint_list *wplp;
7551 if (Training_context & TRAINING_CONTEXT_SPEED) {
7552 s = (int) Player_obj->phys_info.fspeed;
7553 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7554 if (!Training_context_speed_set) {
7555 Training_context_speed_set = 1;
7556 Training_context_speed_timestamp = timestamp();
7560 Training_context_speed_set = 0;
7563 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7564 wplp = &Waypoint_lists[Training_context_path];
7565 if (wplp->count > Training_context_goal_waypoint) {
7566 i = Training_context_goal_waypoint;
7568 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7569 if (d <= Training_context_distance) {
7570 Training_context_at_waypoint = i;
7571 if (Training_context_goal_waypoint == i) {
7572 Training_context_goal_waypoint++;
7573 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7580 if (i == wplp->count)
7583 } while (i != Training_context_goal_waypoint);
7587 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7588 Players_target = Player_ai->target_objnum;
7589 Players_targeted_subsys = Player_ai->targeted_subsys;
7590 Players_target_timestamp = timestamp();
7594 /////////// Following is for event debug view screen
7598 #define EVENT_DEBUG_MAX 5000
7599 #define EVENT_DEBUG_EVENT 0x8000
7601 int Event_debug_index[EVENT_DEBUG_MAX];
7604 void game_add_event_debug_index(int n, int indent)
7606 if (ED_count < EVENT_DEBUG_MAX)
7607 Event_debug_index[ED_count++] = n | (indent << 16);
7610 void game_add_event_debug_sexp(int n, int indent)
7615 if (Sexp_nodes[n].first >= 0) {
7616 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7617 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7621 game_add_event_debug_index(n, indent);
7622 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7623 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7625 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7628 void game_event_debug_init()
7633 for (e=0; e<Num_mission_events; e++) {
7634 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7635 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7639 void game_show_event_debug(float frametime)
7643 int font_height, font_width;
7645 static int scroll_offset = 0;
7647 k = game_check_key();
7653 if (scroll_offset < 0)
7663 scroll_offset -= 20;
7664 if (scroll_offset < 0)
7669 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7673 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7679 gr_set_color_fast(&Color_bright);
7681 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7683 gr_set_color_fast(&Color_normal);
7685 gr_get_string_size(&font_width, &font_height, NOX("test"));
7686 y_max = gr_screen.max_h - font_height - 5;
7690 while (k < ED_count) {
7691 if (y_index > y_max)
7694 z = Event_debug_index[k];
7695 if (z & EVENT_DEBUG_EVENT) {
7697 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7698 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7699 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7700 Mission_events[z].repeat_count, Mission_events[z].interval);
7708 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7709 switch (Sexp_nodes[z & 0x7fff].value) {
7711 strcat(buf, NOX(" (True)"));
7715 strcat(buf, NOX(" (False)"));
7718 case SEXP_KNOWN_TRUE:
7719 strcat(buf, NOX(" (Always true)"));
7722 case SEXP_KNOWN_FALSE:
7723 strcat(buf, NOX(" (Always false)"));
7726 case SEXP_CANT_EVAL:
7727 strcat(buf, NOX(" (Can't eval)"));
7731 case SEXP_NAN_FOREVER:
7732 strcat(buf, NOX(" (Not a number)"));
7737 gr_printf(10, y_index, buf);
7738 y_index += font_height;
7751 extern int Tmap_npixels;
7753 int Tmap_num_too_big = 0;
7754 int Num_models_needing_splitting = 0;
7756 void Time_model( int modelnum )
7758 // mprintf(( "Timing ship '%s'\n", si->name ));
7760 vector eye_pos, model_pos;
7761 matrix eye_orient, model_orient;
7763 polymodel *pm = model_get( modelnum );
7765 int l = strlen(pm->filename);
7767 if ( (l == '/') || (l=='\\') || (l==':')) {
7773 char *pof_file = &pm->filename[l];
7775 int model_needs_splitting = 0;
7777 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7779 for (i=0; i<pm->n_textures; i++ ) {
7780 char filename[1024];
7783 int bmp_num = pm->original_textures[i];
7784 if ( bmp_num > -1 ) {
7785 bm_get_palette(pm->original_textures[i], pal, filename );
7787 bm_get_info( pm->original_textures[i],&w, &h );
7790 if ( (w > 512) || (h > 512) ) {
7791 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7793 model_needs_splitting++;
7796 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7800 if ( model_needs_splitting ) {
7801 Num_models_needing_splitting++;
7803 eye_orient = model_orient = vmd_identity_matrix;
7804 eye_pos = model_pos = vmd_zero_vector;
7806 eye_pos.xyz.z = -pm->rad*2.0f;
7808 vector eye_to_model;
7810 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7811 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7813 fix t1 = timer_get_fixed_seconds();
7816 ta.p = ta.b = ta.h = 0.0f;
7821 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7823 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7825 modelstats_num_polys = modelstats_num_verts = 0;
7827 while( ta.h < PI2 ) {
7830 vm_angles_2_matrix(&m1, &ta );
7831 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7838 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7840 model_clear_instance( modelnum );
7841 model_set_detail_level(0); // use highest detail level
7842 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7850 int k = key_inkey();
7851 if ( k == KEY_ESC ) {
7856 fix t2 = timer_get_fixed_seconds();
7858 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7859 //bitmaps_used_this_frame /= framecount;
7861 modelstats_num_polys /= framecount;
7862 modelstats_num_verts /= framecount;
7864 Tmap_npixels /=framecount;
7867 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7868 fprintf( Time_fp, "\"%s\"\t%.0f\t%d\t%d\t%d\t%d\n", pof_file, i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts, Tmap_npixels );
7869 // fprintf( Time_fp, "%.0f\t%d\t%d\t%d\t%d\n", i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts, Tmap_npixels );
7875 int Time_models = 0;
7876 DCF_BOOL( time_models, Time_models );
7878 void Do_model_timings_test()
7882 if ( !Time_models ) return;
7884 mprintf(( "Timing models!\n" ));
7888 ubyte model_used[MAX_POLYGON_MODELS];
7889 int model_id[MAX_POLYGON_MODELS];
7890 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7895 for (i=0; i<Num_ship_types; i++ ) {
7896 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7898 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7899 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7902 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7903 if ( !Texture_fp ) return;
7905 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7906 if ( !Time_fp ) return;
7908 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7909 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7911 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7912 if ( model_used[i] ) {
7913 Time_model( model_id[i] );
7917 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7918 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7927 // Call this function when you want to inform the player that a feature is not
7928 // enabled in the DEMO version of FreSpace
7929 void game_feature_not_in_demo_popup()
7931 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7934 // format the specified time (fixed point) into a nice string
7935 void game_format_time(fix m_time,char *time_str)
7938 int hours,minutes,seconds;
7941 mtime = f2fl(m_time);
7943 // get the hours, minutes and seconds
7944 hours = (int)(mtime / 3600.0f);
7946 mtime -= (3600.0f * (float)hours);
7948 seconds = (int)mtime%60;
7949 minutes = (int)mtime/60;
7951 // print the hour if necessary
7953 sprintf(time_str,XSTR( "%d:", 201),hours);
7954 // if there are less than 10 minutes, print a leading 0
7956 strcpy(tmp,NOX("0"));
7957 strcat(time_str,tmp);
7961 // print the minutes
7963 sprintf(tmp,XSTR( "%d:", 201),minutes);
7964 strcat(time_str,tmp);
7966 sprintf(time_str,XSTR( "%d:", 201),minutes);
7969 // print the seconds
7971 strcpy(tmp,NOX("0"));
7972 strcat(time_str,tmp);
7974 sprintf(tmp,"%d",seconds);
7975 strcat(time_str,tmp);
7978 // Stuff version string in *str.
7979 void get_version_string(char *str)
7982 if ( FS_VERSION_BUILD == 0 ) {
7983 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7985 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7988 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7990 #elif defined (OEM_BUILD)
7991 strcat(str, " (OEM)");
7997 char myname[_MAX_PATH];
7998 int namelen, major, minor, build, waste;
7999 unsigned int buf_size;
8005 // Find my EXE file name
8006 hMod = GetModuleHandle(NULL);
8007 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
8009 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
8010 infop = (char *)malloc(version_size);
8011 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
8013 // get the product version
8014 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
8015 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
8017 sprintf(str,"Dv%d.%02d",major, minor);
8019 sprintf(str,"v%d.%02d",major, minor);
8024 void get_version_string_short(char *str)
8026 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
8029 // ----------------------------------------------------------------
8031 // OEM UPSELL SCREENS BEGIN
8033 // ----------------------------------------------------------------
8034 #if defined(OEM_BUILD)
8036 #define NUM_OEM_UPSELL_SCREENS 3
8037 #define OEM_UPSELL_SCREEN_DELAY 10000
8039 static int Oem_upsell_bitmaps_loaded = 0;
8040 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
8041 static int Oem_upsell_screen_number = 0;
8042 static int Oem_upsell_show_next_bitmap_time;
8045 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
8058 static int Oem_normal_cursor = -1;
8059 static int Oem_web_cursor = -1;
8060 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
8061 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
8063 void oem_upsell_next_screen()
8065 Oem_upsell_screen_number++;
8066 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
8067 // extra long delay, mouse shown on last upsell
8068 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
8072 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8076 void oem_upsell_load_bitmaps()
8080 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8081 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
8085 void oem_upsell_unload_bitmaps()
8089 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8090 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
8091 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
8096 Oem_upsell_bitmaps_loaded = 0;
8099 // clickable hotspot on 3rd OEM upsell screen
8100 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
8102 28, 350, 287, 96 // x, y, w, h
8105 45, 561, 460, 152 // x, y, w, h
8109 void oem_upsell_show_screens()
8111 int current_time, k;
8114 if ( !Oem_upsell_bitmaps_loaded ) {
8115 oem_upsell_load_bitmaps();
8116 Oem_upsell_bitmaps_loaded = 1;
8119 // may use upsell screens more than once
8120 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8121 Oem_upsell_screen_number = 0;
8127 int nframes; // used to pass, not really needed (should be 1)
8128 Oem_normal_cursor = gr_get_cursor_bitmap();
8129 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
8130 Assert(Oem_web_cursor >= 0);
8131 if (Oem_web_cursor < 0) {
8132 Oem_web_cursor = Oem_normal_cursor;
8137 //oem_reset_trailer_timer();
8139 current_time = timer_get_milliseconds();
8144 // advance screen on keypress or timeout
8145 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
8146 oem_upsell_next_screen();
8149 // check if we are done
8150 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
8151 Oem_upsell_screen_number--;
8154 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
8159 // show me the upsell
8160 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
8161 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
8165 // if this is the 3rd upsell, make it clickable, d00d
8166 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
8168 int button_state = mouse_get_pos(&mx, &my);
8169 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])
8170 && (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]) )
8173 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
8176 if (button_state & MOUSE_LEFT_BUTTON) {
8178 multi_pxo_url(OEM_UPSELL_URL);
8182 // switch cursor back to normal one
8183 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8188 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8198 oem_upsell_unload_bitmaps();
8200 // switch cursor back to normal one
8201 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8205 #endif // defined(OEM_BUILD)
8206 // ----------------------------------------------------------------
8208 // OEM UPSELL SCREENS END
8210 // ----------------------------------------------------------------
8214 // ----------------------------------------------------------------
8216 // DEMO UPSELL SCREENS BEGIN
8218 // ----------------------------------------------------------------
8220 #if defined(FS2_DEMO) || defined(FS1_DEMO)
8223 #define NUM_DEMO_UPSELL_SCREENS 2
8225 #define NUM_DEMO_UPSELL_SCREENS 4
8227 #define DEMO_UPSELL_SCREEN_DELAY 3000
8229 static int Demo_upsell_bitmaps_loaded = 0;
8230 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
8231 static int Demo_upsell_screen_number = 0;
8232 static int Demo_upsell_show_next_bitmap_time;
8235 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
8261 void demo_upsell_next_screen()
8263 Demo_upsell_screen_number++;
8264 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
8265 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
8267 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8271 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
8272 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8273 #ifndef HARDWARE_ONLY
8274 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8281 void demo_upsell_load_bitmaps()
8285 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8286 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
8290 void demo_upsell_unload_bitmaps()
8294 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8295 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8296 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8301 Demo_upsell_bitmaps_loaded = 0;
8304 void demo_upsell_show_screens()
8306 int current_time, k;
8309 if ( !Demo_upsell_bitmaps_loaded ) {
8310 demo_upsell_load_bitmaps();
8311 Demo_upsell_bitmaps_loaded = 1;
8314 // may use upsell screens more than once
8315 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8316 Demo_upsell_screen_number = 0;
8323 demo_reset_trailer_timer();
8325 current_time = timer_get_milliseconds();
8332 // don't time out, wait for keypress
8334 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8335 demo_upsell_next_screen();
8340 demo_upsell_next_screen();
8343 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8344 Demo_upsell_screen_number--;
8347 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8352 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8353 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8358 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8368 demo_upsell_unload_bitmaps();
8373 // ----------------------------------------------------------------
8375 // DEMO UPSELL SCREENS END
8377 // ----------------------------------------------------------------
8380 // ----------------------------------------------------------------
8382 // Subspace Ambient Sound START
8384 // ----------------------------------------------------------------
8386 static int Subspace_ambient_left_channel = -1;
8387 static int Subspace_ambient_right_channel = -1;
8390 void game_start_subspace_ambient_sound()
8392 if ( Subspace_ambient_left_channel < 0 ) {
8393 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8396 if ( Subspace_ambient_right_channel < 0 ) {
8397 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8401 void game_stop_subspace_ambient_sound()
8403 if ( Subspace_ambient_left_channel >= 0 ) {
8404 snd_stop(Subspace_ambient_left_channel);
8405 Subspace_ambient_left_channel = -1;
8408 if ( Subspace_ambient_right_channel >= 0 ) {
8409 snd_stop(Subspace_ambient_right_channel);
8410 Subspace_ambient_right_channel = -1;
8414 // ----------------------------------------------------------------
8416 // Subspace Ambient Sound END
8418 // ----------------------------------------------------------------
8420 // ----------------------------------------------------------------
8422 // CDROM detection code START
8424 // ----------------------------------------------------------------
8426 #define CD_SIZE_72_MINUTE_MAX (697000000)
8428 uint game_get_cd_used_space(char *path)
8432 char use_path[512] = "";
8433 char sub_path[512] = "";
8434 WIN32_FIND_DATA find;
8437 // recurse through all files and directories
8438 strcpy(use_path, path);
8439 strcat(use_path, "*.*");
8440 find_handle = FindFirstFile(use_path, &find);
8443 if(find_handle == INVALID_HANDLE_VALUE){
8449 // subdirectory. make sure to ignore . and ..
8450 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8452 strcpy(sub_path, path);
8453 strcat(sub_path, find.cFileName);
8454 strcat(sub_path, "\\");
8455 total += game_get_cd_used_space(sub_path);
8457 total += (uint)find.nFileSizeLow;
8459 } while(FindNextFile(find_handle, &find));
8462 FindClose(find_handle);
8474 // if volume_name is non-null, the CD name must match that
8475 int find_freespace_cd(char *volume_name)
8478 char oldpath[MAX_PATH];
8482 int volume_match = 0;
8486 GetCurrentDirectory(MAX_PATH, oldpath);
8488 for (i = 0; i < 26; i++)
8494 path[0] = (char)('A'+i);
8495 if (GetDriveType(path) == DRIVE_CDROM) {
8497 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8498 nprintf(("CD", "CD volume: %s\n", volume));
8500 // check for any CD volume
8501 int volume1_present = 0;
8502 int volume2_present = 0;
8503 int volume3_present = 0;
8505 char full_check[512] = "";
8507 // look for setup.exe
8508 strcpy(full_check, path);
8509 strcat(full_check, "setup.exe");
8510 find_handle = _findfirst(full_check, &find);
8511 if(find_handle != -1){
8512 volume1_present = 1;
8513 _findclose(find_handle);
8516 // look for intro.mve
8517 strcpy(full_check, path);
8518 strcat(full_check, "intro.mve");
8519 find_handle = _findfirst(full_check, &find);
8520 if(find_handle != -1){
8521 volume2_present = 1;
8522 _findclose(find_handle);
8525 // look for endpart1.mve
8526 strcpy(full_check, path);
8527 strcat(full_check, "endpart1.mve");
8528 find_handle = _findfirst(full_check, &find);
8529 if(find_handle != -1){
8530 volume3_present = 1;
8531 _findclose(find_handle);
8534 // see if we have the specific CD we're looking for
8535 if ( volume_name ) {
8537 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8541 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8545 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8549 if ( volume1_present || volume2_present || volume3_present ) {
8554 // here's where we make sure that CD's 2 and 3 are not just ripped - check to make sure its capacity is > 697,000,000 bytes
8555 if ( volume_match ){
8557 // we don't care about CD1 though. let it be whatever size it wants, since the game will demand CD's 2 and 3 at the proper time
8558 if(volume2_present || volume3_present) {
8559 // first step - check to make sure its a cdrom
8560 if(GetDriveType(path) != DRIVE_CDROM){
8564 #if !defined(OEM_BUILD)
8565 // oem not on 80 min cds, so dont check tha size
8567 uint used_space = game_get_cd_used_space(path);
8568 if(used_space < CD_SIZE_72_MINUTE_MAX){
8571 #endif // !defined(OEM_BUILD)
8579 #endif // RELEASE_REAL
8585 SetCurrentDirectory(oldpath);
8594 int set_cdrom_path(int drive_num)
8598 if (drive_num < 0) { //no CD
8600 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8603 strcpy(Game_CDROM_dir,""); //set directory
8607 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8623 i = find_freespace_cd();
8625 rval = set_cdrom_path(i);
8629 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8631 nprintf(("CD", "FreeSpace CD not found\n"));
8639 int Last_cd_label_found = 0;
8640 char Last_cd_label[256];
8642 int game_cd_changed()
8649 if ( strlen(Game_CDROM_dir) == 0 ) {
8653 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8655 if ( found != Last_cd_label_found ) {
8656 Last_cd_label_found = found;
8658 mprintf(( "CD '%s' was inserted\n", label ));
8661 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8665 if ( Last_cd_label_found ) {
8666 if ( !stricmp( Last_cd_label, label )) {
8667 //mprintf(( "CD didn't change\n" ));
8669 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8673 // none found before, none found now.
8674 //mprintf(( "still no CD...\n" ));
8678 Last_cd_label_found = found;
8680 strcpy( Last_cd_label, label );
8682 strcpy( Last_cd_label, "" );
8693 // check if _any_ FreeSpace2 CDs are in the drive
8694 // return: 1 => CD now in drive
8695 // 0 => Could not find CD, they refuse to put it in the drive
8696 int game_do_cd_check(char *volume_name)
8698 #if !defined(GAME_CD_CHECK)
8704 int num_attempts = 0;
8705 int refresh_files = 0;
8707 int path_set_ok, popup_rval;
8709 cd_drive_num = find_freespace_cd(volume_name);
8710 path_set_ok = set_cdrom_path(cd_drive_num);
8711 if ( path_set_ok ) {
8713 if ( refresh_files ) {
8725 // no CD found, so prompt user
8726 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8728 if ( popup_rval != 1 ) {
8733 if ( num_attempts++ > 5 ) {
8744 // check if _any_ FreeSpace2 CDs are in the drive
8745 // return: 1 => CD now in drive
8746 // 0 => Could not find CD, they refuse to put it in the drive
8747 int game_do_cd_check_specific(char *volume_name, int cdnum)
8752 int num_attempts = 0;
8753 int refresh_files = 0;
8755 int path_set_ok, popup_rval;
8757 cd_drive_num = find_freespace_cd(volume_name);
8758 path_set_ok = set_cdrom_path(cd_drive_num);
8759 if ( path_set_ok ) {
8761 if ( refresh_files ) {
8772 // no CD found, so prompt user
8773 #if defined(DVD_MESSAGE_HACK)
8774 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8776 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8779 if ( popup_rval != 1 ) {
8784 if ( num_attempts++ > 5 ) {
8794 // only need to do this in RELEASE_REAL
8795 int game_do_cd_mission_check(char *filename)
8801 fs_builtin_mission *m = game_find_builtin_mission(filename);
8803 // check for changed CD
8804 if(game_cd_changed()){
8809 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8813 // not builtin, so do a general check (any FS2 CD will do)
8815 return game_do_cd_check();
8818 // does not have any CD requirement, do a general check
8819 if(strlen(m->cd_volume) <= 0){
8820 return game_do_cd_check();
8824 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8826 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8829 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8833 return game_do_cd_check();
8836 // did we find the cd?
8837 if(find_freespace_cd(m->cd_volume) >= 0){
8841 // make sure the volume exists
8842 int num_attempts = 0;
8843 int refresh_files = 0;
8845 int path_set_ok, popup_rval;
8847 cd_drive_num = find_freespace_cd(m->cd_volume);
8848 path_set_ok = set_cdrom_path(cd_drive_num);
8849 if ( path_set_ok ) {
8851 if ( refresh_files ) {
8858 // no CD found, so prompt user
8859 #if defined(DVD_MESSAGE_HACK)
8860 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8862 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8866 if ( popup_rval != 1 ) {
8871 if ( num_attempts++ > 5 ) {
8883 // ----------------------------------------------------------------
8885 // CDROM detection code END
8887 // ----------------------------------------------------------------
8889 // ----------------------------------------------------------------
8891 // Language Autodetection stuff
8894 // this layout order must match Lcl_languages in localize.cpp in order for the
8895 // correct language to be detected
8896 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
8898 1366105450, // English
8900 589986744, // English
8902 -1132430286, // German
8904 -1131728960, // Polish
8907 // default setting is "-1" to use config file with English as fall back
8908 // DO NOT change the default setting here or something uncouth might happen
8909 // in the localization code
8915 // try and open the file to verify
8916 CFILE *detect = cfopen("font01.vf", "rb");
8918 // will use default setting if something went wrong
8923 // get the long checksum of the file
8925 cfseek(detect, 0, SEEK_SET);
8926 cf_chksum_long(detect, &file_checksum);
8930 // now compare the checksum/filesize against known #'s
8931 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8932 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8937 // notify if a match was not found, include detected checksum
8938 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8939 printf("Using default language...\n\n");
8945 // End Auto Lang stuff
8947 // ----------------------------------------------------------------
8949 // ----------------------------------------------------------------
8950 // SHIPS TBL VERIFICATION STUFF
8953 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8954 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8955 #define NUM_SHIPS_TBL_CHECKSUMS 3
8957 #define NUM_SHIPS_TBL_CHECKSUMS 1
8961 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8962 1696074201, // FS2 demo
8965 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8966 1603375034, // FS1 DEMO
8969 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8970 -129679197, // FS1 Full 1.06 (US)
8971 7762567, // FS1 SilentThreat
8972 1555372475 // FS1 Full 1.06 (German)
8976 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8977 -463907578, // US - beta 1
8978 1696074201, // FS2 demo
8981 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8982 // -1022810006, // 1.0 FULL
8983 -1254285366 // 1.2 FULL (German)
8987 void verify_ships_tbl()
8991 Game_ships_tbl_valid = 1;
8997 // detect if the packfile exists
8998 CFILE *detect = cfopen("ships.tbl", "rb");
8999 Game_ships_tbl_valid = 0;
9003 Game_ships_tbl_valid = 0;
9007 // get the long checksum of the file
9009 cfseek(detect, 0, SEEK_SET);
9010 cf_chksum_long(detect, &file_checksum);
9014 // now compare the checksum/filesize against known #'s
9015 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
9016 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
9017 Game_ships_tbl_valid = 1;
9024 DCF(shipspew, "display the checksum for the current ships.tbl")
9027 CFILE *detect = cfopen("ships.tbl", "rb");
9028 // get the long checksum of the file
9030 cfseek(detect, 0, SEEK_SET);
9031 cf_chksum_long(detect, &file_checksum);
9034 dc_printf("%d", file_checksum);
9037 // ----------------------------------------------------------------
9038 // WEAPONS TBL VERIFICATION STUFF
9041 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
9042 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
9043 #define NUM_WEAPONS_TBL_CHECKSUMS 3
9045 #define NUM_WEAPONS_TBL_CHECKSUMS 1
9049 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9050 -266420030, // demo 1
9053 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9054 -1246928725, // FS1 DEMO
9057 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9058 -834598107, // FS1 1.06 Full (US)
9059 -1652231417, // FS1 SilentThreat
9060 720209793 // FS1 1.06 Full (German)
9064 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9065 141718090, // US - beta 1
9066 -266420030, // demo 1
9069 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9070 // 399297860, // 1.0 FULL
9071 -553984927 // 1.2 FULL (german)
9075 void verify_weapons_tbl()
9079 Game_weapons_tbl_valid = 1;
9082 int file_checksum; // Game_weapons_tbl_checksums[] is signed, so...
9085 // detect if the packfile exists
9086 CFILE *detect = cfopen("weapons.tbl", "rb");
9087 Game_weapons_tbl_valid = 0;
9091 Game_weapons_tbl_valid = 0;
9095 // get the long checksum of the file
9097 cfseek(detect, 0, SEEK_SET);
9098 cf_chksum_long(detect, &file_checksum);
9102 // now compare the checksum/filesize against known #'s
9103 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
9104 if(Game_weapons_tbl_checksums[idx] == file_checksum){
9105 Game_weapons_tbl_valid = 1;
9112 DCF(wepspew, "display the checksum for the current weapons.tbl")
9115 CFILE *detect = cfopen("weapons.tbl", "rb");
9116 // get the long checksum of the file
9118 cfseek(detect, 0, SEEK_SET);
9119 cf_chksum_long(detect, &file_checksum);
9122 dc_printf("%d", file_checksum);
9125 // if the game is running using hacked data
9126 int game_hacked_data()
9129 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
9137 void display_title_screen()
9139 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
9140 ///int title_bitmap;
9143 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
9144 if (title_bitmap == -1) {
9150 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9151 extern void d3d_start_frame();
9157 gr_set_bitmap(title_bitmap);
9164 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9165 extern void d3d_stop_frame();
9173 bm_unload(title_bitmap);
9174 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
9177 // return true if the game is running with "low memory", which is less than 48MB
9178 bool game_using_low_mem()
9180 if (Use_low_mem == 0) {