2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.13 2002/06/02 04:26:34 relnev
13 * Revision 1.12 2002/06/02 00:31:35 relnev
14 * implemented osregistry
16 * Revision 1.11 2002/06/01 09:00:34 relnev
17 * silly debug memmanager
19 * Revision 1.10 2002/06/01 07:12:32 relnev
20 * a few NDEBUG updates.
22 * removed a few warnings.
24 * Revision 1.9 2002/05/31 03:05:59 relnev
27 * Revision 1.8 2002/05/29 02:52:32 theoddone33
28 * Enable OpenGL renderer
30 * Revision 1.7 2002/05/28 08:52:03 relnev
31 * implemented two assembly stubs.
33 * cleaned up a few warnings.
35 * added a little demo hackery to make it progress a little farther.
37 * Revision 1.6 2002/05/28 06:28:20 theoddone33
38 * Filesystem mods, actually reads some data files now
40 * Revision 1.5 2002/05/28 04:07:28 theoddone33
41 * New graphics stubbing arrangement
43 * Revision 1.4 2002/05/27 22:46:52 theoddone33
44 * Remove more undefined symbols
46 * Revision 1.3 2002/05/26 23:31:18 relnev
47 * added a few files that needed to be compiled
49 * freespace.cpp: now compiles
51 * Revision 1.2 2002/05/07 03:16:44 theoddone33
52 * The Great Newline Fix
54 * Revision 1.1.1.1 2002/05/03 03:28:09 root
58 * 201 6/16/00 3:15p Jefff
59 * sim of the year dvd version changes, a few german soty localization
62 * 200 11/03/99 11:06a Jefff
65 * 199 10/26/99 5:07p Jamest
66 * fixed jeffs dumb debug code
68 * 198 10/25/99 5:53p Jefff
69 * call control_config_common_init() on startup
71 * 197 10/14/99 10:18a Daveb
72 * Fixed incorrect CD checking problem on standalone server.
74 * 196 10/13/99 9:22a Daveb
75 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
76 * related to movies. Fixed launcher spawning from PXO screen.
78 * 195 10/06/99 11:05a Jefff
79 * new oem upsell 3 hotspot coords
81 * 194 10/06/99 10:31a Jefff
84 * 193 10/01/99 9:10a Daveb
87 * 192 9/15/99 4:57a Dave
88 * Updated ships.tbl checksum
90 * 191 9/15/99 3:58a Dave
91 * Removed framerate warning at all times.
93 * 190 9/15/99 3:16a Dave
94 * Remove mt-011.fs2 from the builtin mission list.
96 * 189 9/15/99 1:45a Dave
97 * Don't init joystick on standalone. Fixed campaign mode on standalone.
98 * Fixed no-score-report problem in TvT
100 * 188 9/14/99 6:08a Dave
101 * Updated (final) single, multi, and campaign list.
103 * 187 9/14/99 3:26a Dave
104 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
105 * respawn-too-early problem. Made a few crash points safe.
107 * 186 9/13/99 4:52p Dave
110 * 185 9/12/99 8:09p Dave
111 * Fixed problem where skip-training button would cause mission messages
112 * not to get paged out for the current mission.
114 * 184 9/10/99 11:53a Dave
115 * Shutdown graphics before sound to eliminate apparent lockups when
116 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
118 * 183 9/09/99 11:40p Dave
119 * Handle an Assert() in beam code. Added supernova sounds. Play the right
120 * 2 end movies properly, based upon what the player did in the mission.
122 * 182 9/08/99 10:29p Dave
123 * Make beam sound pausing and unpausing much safer.
125 * 181 9/08/99 10:01p Dave
126 * Make sure game won't run in a drive's root directory. Make sure
127 * standalone routes suqad war messages properly to the host.
129 * 180 9/08/99 3:22p Dave
130 * Updated builtin mission list.
132 * 179 9/08/99 12:01p Jefff
133 * fixed Game_builtin_mission_list typo on Training-2.fs2
135 * 178 9/08/99 9:48a Andsager
136 * Add force feedback for engine wash.
138 * 177 9/07/99 4:01p Dave
139 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
140 * does everything properly (setting up address when binding). Remove
141 * black rectangle background from UI_INPUTBOX.
143 * 176 9/13/99 2:40a Dave
144 * Comment in full 80 minute CD check for RELEASE_REAL builds.
146 * 175 9/06/99 6:38p Dave
147 * Improved CD detection code.
149 * 174 9/06/99 1:30a Dave
150 * Intermediate checkin. Started on enforcing CD-in-drive to play the
153 * 173 9/06/99 1:16a Dave
154 * Make sure the user sees the intro movie.
156 * 172 9/04/99 8:00p Dave
157 * Fixed up 1024 and 32 bit movie support.
159 * 171 9/03/99 1:32a Dave
160 * CD checking by act. Added support to play 2 cutscenes in a row
161 * seamlessly. Fixed super low level cfile bug related to files in the
162 * root directory of a CD. Added cheat code to set campaign mission # in
165 * 170 9/01/99 10:49p Dave
166 * Added nice SquadWar checkbox to the client join wait screen.
168 * 169 9/01/99 10:14a Dave
171 * 168 8/29/99 4:51p Dave
172 * Fixed damaged checkin.
174 * 167 8/29/99 4:18p Andsager
175 * New "burst" limit for friendly damage. Also credit more damage done
176 * against large friendly ships.
178 * 166 8/27/99 6:38p Alanl
179 * crush the blasted repeating messages bug
181 * 164 8/26/99 9:09p Dave
182 * Force framerate check in everything but a RELEASE_REAL build.
184 * 163 8/26/99 9:45a Dave
185 * First pass at easter eggs and cheats.
187 * 162 8/24/99 8:55p Dave
188 * Make sure nondimming pixels work properly in tech menu.
190 * 161 8/24/99 1:49a Dave
191 * Fixed client-side afterburner stuttering. Added checkbox for no version
192 * checking on PXO join. Made button info passing more friendly between
195 * 160 8/22/99 5:53p Dave
196 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
197 * instead of ship designations for multiplayer players.
199 * 159 8/22/99 1:19p Dave
200 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
201 * which d3d cards are detected.
203 * 158 8/20/99 2:09p Dave
204 * PXO banner cycling.
206 * 157 8/19/99 10:59a Dave
207 * Packet loss detection.
209 * 156 8/19/99 10:12a Alanl
210 * preload mission-specific messages on machines greater than 48MB
212 * 155 8/16/99 4:04p Dave
213 * Big honking checkin.
215 * 154 8/11/99 5:54p Dave
216 * Fixed collision problem. Fixed standalone ghost problem.
218 * 153 8/10/99 7:59p Jefff
221 * 152 8/10/99 6:54p Dave
222 * Mad optimizations. Added paging to the nebula effect.
224 * 151 8/10/99 3:44p Jefff
225 * loads Intelligence information on startup
227 * 150 8/09/99 3:47p Dave
228 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
229 * non-nebula missions.
231 * 149 8/09/99 2:21p Andsager
232 * Fix patching from multiplayer direct to launcher update tab.
234 * 148 8/09/99 10:36a Dave
235 * Version info for game.
237 * 147 8/06/99 9:46p Dave
238 * Hopefully final changes for the demo.
240 * 146 8/06/99 3:34p Andsager
241 * Make title version info "(D)" -> "D" show up nicely
243 * 145 8/06/99 2:59p Adamp
244 * Fixed NT launcher/update problem.
246 * 144 8/06/99 1:52p Dave
247 * Bumped up MAX_BITMAPS for the demo.
249 * 143 8/06/99 12:17p Andsager
250 * Demo: down to just 1 demo dog
252 * 142 8/05/99 9:39p Dave
253 * Yet another new checksum.
255 * 141 8/05/99 6:19p Dave
256 * New demo checksums.
258 * 140 8/05/99 5:31p Andsager
259 * Up demo version 1.01
261 * 139 8/05/99 4:22p Andsager
262 * No time limit on upsell screens. Reverse order of display of upsell
265 * 138 8/05/99 4:17p Dave
266 * Tweaks to client interpolation.
268 * 137 8/05/99 3:52p Danw
270 * 136 8/05/99 3:01p Danw
272 * 135 8/05/99 2:43a Anoop
273 * removed duplicate definition.
275 * 134 8/05/99 2:13a Dave
278 * 133 8/05/99 2:05a Dave
281 * 132 8/05/99 1:22a Andsager
284 * 131 8/04/99 9:51p Andsager
285 * Add title screen to demo
287 * 130 8/04/99 6:47p Jefff
288 * fixed link error resulting from #ifdefs
290 * 129 8/04/99 6:26p Dave
291 * Updated ship tbl checksum.
293 * 128 8/04/99 5:40p Andsager
294 * Add multiple demo dogs
296 * 127 8/04/99 5:36p Andsager
297 * Show upsell screens at end of demo campaign before returning to main
300 * 126 8/04/99 11:42a Danw
301 * tone down EAX reverb
303 * 125 8/04/99 11:23a Dave
304 * Updated demo checksums.
306 * 124 8/03/99 11:02p Dave
307 * Maybe fixed sync problems in multiplayer.
309 * 123 8/03/99 6:21p Jefff
312 * 122 8/03/99 3:44p Andsager
313 * Launch laucher if trying to run FS without first having configured
316 * 121 8/03/99 12:45p Dave
319 * 120 8/02/99 9:13p Dave
322 * 119 7/30/99 10:31p Dave
323 * Added comm menu to the configurable hud files.
325 * 118 7/30/99 5:17p Andsager
326 * first fs2demo checksums
328 * 117 7/29/99 3:09p Anoop
330 * 116 7/29/99 12:05a Dave
331 * Nebula speed optimizations.
333 * 115 7/27/99 8:59a Andsager
334 * Make major, minor version consistent for all builds. Only show major
335 * and minor for launcher update window.
337 * 114 7/26/99 5:50p Dave
338 * Revised ingame join. Better? We'll see....
340 * 113 7/26/99 5:27p Andsager
341 * Add training mission as builtin to demo build
343 * 112 7/24/99 1:54p Dave
344 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
347 * 111 7/22/99 4:00p Dave
348 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
350 * 110 7/21/99 8:10p Dave
351 * First run of supernova effect.
353 * 109 7/20/99 1:49p Dave
354 * Peter Drake build. Fixed some release build warnings.
356 * 108 7/19/99 2:26p Andsager
357 * set demo multiplayer missions
359 * 107 7/18/99 5:19p Dave
360 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
362 * 106 7/16/99 1:50p Dave
363 * 8 bit aabitmaps. yay.
365 * 105 7/15/99 3:07p Dave
366 * 32 bit detection support. Mouse coord commandline.
368 * 104 7/15/99 2:13p Dave
369 * Added 32 bit detection.
371 * 103 7/15/99 9:20a Andsager
372 * FS2_DEMO initial checkin
374 * 102 7/14/99 11:02a Dave
375 * Skill level default back to easy. Blech.
377 * 101 7/09/99 5:54p Dave
378 * Seperated cruiser types into individual types. Added tons of new
379 * briefing icons. Campaign screen.
381 * 100 7/08/99 4:43p Andsager
382 * New check for sparky_hi and print if not found.
384 * 99 7/08/99 10:53a Dave
385 * New multiplayer interpolation scheme. Not 100% done yet, but still
386 * better than the old way.
388 * 98 7/06/99 4:24p Dave
389 * Mid-level checkin. Starting on some potentially cool multiplayer
392 * 97 7/06/99 3:35p Andsager
393 * Allow movie to play before red alert mission.
395 * 96 7/03/99 5:50p Dave
396 * Make rotated bitmaps draw properly in padlock views.
398 * 95 7/02/99 9:55p Dave
399 * Player engine wash sound.
401 * 94 7/02/99 4:30p Dave
402 * Much more sophisticated lightning support.
404 * 93 6/29/99 7:52p Dave
405 * Put in exception handling in FS2.
407 * 92 6/22/99 9:37p Dave
408 * Put in pof spewing.
410 * 91 6/16/99 4:06p Dave
411 * New pilot info popup. Added new draw-bitmap-as-poly function.
413 * 90 6/15/99 1:56p Andsager
414 * For release builds, allow start up in high res only with
417 * 89 6/15/99 9:34a Dave
418 * Fixed key checking in single threaded version of the stamp notification
421 * 88 6/09/99 2:55p Andsager
422 * Allow multiple asteroid subtypes (of large, medium, small) and follow
425 * 87 6/08/99 1:14a Dave
426 * Multi colored hud test.
428 * 86 6/04/99 9:52a Dave
429 * Fixed some rendering problems.
431 * 85 6/03/99 10:15p Dave
432 * Put in temporary main hall screen.
434 * 84 6/02/99 6:18p Dave
435 * Fixed TNT lockup problems! Wheeeee!
437 * 83 6/01/99 3:52p Dave
438 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
439 * dead popup, pxo find player popup, pxo private room popup.
441 * 82 5/26/99 1:28p Jasenw
442 * changed coords for loading ani
444 * 81 5/26/99 11:46a Dave
445 * Added ship-blasting lighting and made the randomization of lighting
446 * much more customizable.
448 * 80 5/24/99 5:45p Dave
449 * Added detail levels to the nebula, with a decent speedup. Split nebula
450 * lightning into its own section.
468 #include "systemvars.h"
473 #include "starfield.h"
474 #include "lighting.h"
479 #include "fireballs.h"
483 #include "floating.h"
484 #include "gamesequence.h"
486 #include "optionsmenu.h"
487 #include "playermenu.h"
488 #include "trainingmenu.h"
489 #include "techmenu.h"
492 #include "hudmessage.h"
494 #include "missiongoals.h"
495 #include "missionparse.h"
500 #include "multiutil.h"
501 #include "multimsgs.h"
505 #include "freespace.h"
506 #include "managepilot.h"
508 #include "contexthelp.h"
511 #include "missionbrief.h"
512 #include "missiondebrief.h"
514 #include "missionshipchoice.h"
516 #include "hudconfig.h"
517 #include "controlsconfig.h"
518 #include "missionmessage.h"
519 #include "missiontraining.h"
521 #include "hudtarget.h"
525 #include "eventmusic.h"
526 #include "animplay.h"
527 #include "missionweaponchoice.h"
528 #include "missionlog.h"
529 #include "audiostr.h"
531 #include "missioncampaign.h"
533 #include "missionhotkey.h"
534 #include "objectsnd.h"
535 #include "cmeasure.h"
537 #include "linklist.h"
538 #include "shockwave.h"
539 #include "afterburner.h"
544 #include "stand_gui.h"
545 #include "pcxutils.h"
546 #include "hudtargetbox.h"
547 #include "multi_xfer.h"
548 #include "hudescort.h"
549 #include "multiutil.h"
552 #include "multiteamselect.h"
555 #include "readyroom.h"
556 #include "mainhallmenu.h"
557 #include "multilag.h"
559 #include "particle.h"
561 #include "multi_ingame.h"
562 #include "snazzyui.h"
563 #include "asteroid.h"
564 #include "popupdead.h"
565 #include "multi_voice.h"
566 #include "missioncmdbrief.h"
567 #include "redalert.h"
568 #include "gameplayhelp.h"
569 #include "multilag.h"
570 #include "staticrand.h"
571 #include "multi_pmsg.h"
572 #include "levelpaging.h"
573 #include "observer.h"
574 #include "multi_pause.h"
575 #include "multi_endgame.h"
576 #include "cutscenes.h"
577 #include "multi_respawn.h"
578 // #include "movie.h"
579 #include "multi_obj.h"
580 #include "multi_log.h"
582 #include "localize.h"
583 #include "osregistry.h"
584 #include "barracks.h"
585 #include "missionpause.h"
587 #include "alphacolors.h"
588 #include "objcollide.h"
591 #include "neblightning.h"
592 #include "shipcontrails.h"
595 #include "multi_dogfight.h"
596 #include "multi_rate.h"
597 #include "muzzleflash.h"
601 #include "mainhalltemp.h"
602 #include "exceptionhandler.h"
606 #include "supernova.h"
607 #include "hudshield.h"
608 // #include "names.h"
610 #include "missionloopbrief.h"
614 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
620 // 1.00.04 5/26/98 MWA -- going final (12 pm)
621 // 1.00.03 5/26/98 MWA -- going final (3 am)
622 // 1.00.02 5/25/98 MWA -- going final
623 // 1.00.01 5/25/98 MWA -- going final
624 // 0.90 5/21/98 MWA -- getting ready for final.
625 // 0.10 4/9/98. Set by MK.
627 // Demo version: (obsolete since DEMO codebase split from tree)
628 // 0.03 4/10/98 AL. Interplay rev
629 // 0.02 4/8/98 MK. Increased when this system was modified.
630 // 0.01 4/7/98? AL. First release to Interplay QA.
633 // 1.00 5/28/98 AL. First release to Interplay QA.
635 void game_level_init(int seed = -1);
636 void game_post_level_init();
637 void game_do_frame();
638 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
639 void game_reset_time();
640 void game_show_framerate(); // draws framerate in lower right corner
642 int Game_no_clear = 0;
644 int Pofview_running = 0;
645 int Nebedit_running = 0;
647 typedef struct big_expl_flash {
648 float max_flash_intensity; // max intensity
649 float cur_flash_intensity; // cur intensity
650 int flash_start; // start time
653 #define FRAME_FILTER 16
655 #define DEFAULT_SKILL_LEVEL 1
656 int Game_skill_level = DEFAULT_SKILL_LEVEL;
658 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
659 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
661 #define EXE_FNAME ("fs2.exe")
662 #define LAUNCHER_FNAME ("freespace2.exe")
664 // JAS: Code for warphole camera.
665 // Needs to be cleaned up.
666 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
667 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
668 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
669 matrix Camera_orient = IDENTITY_MATRIX;
670 float Camera_damping = 1.0f;
671 float Camera_time = 0.0f;
672 float Warpout_time = 0.0f;
673 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
674 int Warpout_sound = -1;
676 int Use_joy_mouse = 0;
677 int Use_palette_flash = 1;
679 int Use_fullscreen_at_startup = 0;
681 int Show_area_effect = 0;
682 object *Last_view_target = NULL;
684 int dogfight_blown = 0;
687 float frametimes[FRAME_FILTER];
688 float frametotal = 0.0f;
692 int Show_framerate = 0;
694 int Show_framerate = 1;
697 int Framerate_cap = 120;
700 int Show_target_debug_info = 0;
701 int Show_target_weapons = 0;
705 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
708 int Debug_octant = -1;
710 fix Game_time_compression = F1_0;
712 // if the ships.tbl the player has is valid
713 int Game_ships_tbl_valid = 0;
715 // if the weapons.tbl the player has is valid
716 int Game_weapons_tbl_valid = 0;
720 extern int Player_attacking_enabled;
724 int Pre_player_entry;
726 int Fred_running = 0;
727 char Game_current_mission_filename[MAX_FILENAME_LEN];
728 int game_single_step = 0;
729 int last_single_step=0;
731 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
732 extern int MSG_WINDOW_Y_START;
733 extern int MSG_WINDOW_HEIGHT;
735 int game_zbuffer = 1;
736 //static int Game_music_paused;
737 static int Game_paused;
741 #define EXPIRE_BAD_CHECKSUM 1
742 #define EXPIRE_BAD_TIME 2
744 extern void ssm_init();
745 extern void ssm_level_init();
746 extern void ssm_process();
748 // static variable to contain the time this version was built
749 // commented out for now until
750 // I figure out how to get the username into the file
751 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
753 // defines and variables used for dumping frame for making trailers.
755 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
756 int Debug_dump_trigger = 0;
757 int Debug_dump_frame_count;
758 int Debug_dump_frame_num = 0;
759 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
762 // amount of time to wait after the player has died before we display the death died popup
763 #define PLAYER_DIED_POPUP_WAIT 2500
764 int Player_died_popup_wait = -1;
765 int Player_multi_died_check = -1;
767 // builtin mission list stuff
769 int Game_builtin_mission_count = 6;
770 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
771 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
772 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
773 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
774 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
775 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
776 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
778 #elif defined(PD_BUILD)
779 int Game_builtin_mission_count = 4;
780 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
781 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
782 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
783 { "sm1-01", (FSB_FROM_VOLITION), "" },
784 { "sm1-05", (FSB_FROM_VOLITION), "" },
786 #elif defined(MULTIPLAYER_BETA)
787 int Game_builtin_mission_count = 17;
788 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
790 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
791 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
792 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
793 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
794 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
795 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
796 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
797 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
798 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
799 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
800 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
801 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
802 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
803 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
804 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
805 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
806 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
808 #elif defined(OEM_BUILD)
809 int Game_builtin_mission_count = 17;
810 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
811 // oem version - act 1 only
812 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
815 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
816 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
817 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
818 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
819 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
820 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
821 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
822 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
823 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
824 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
825 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
826 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
827 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
828 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
829 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
830 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
833 int Game_builtin_mission_count = 92;
834 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
835 // single player campaign
836 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
839 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
841 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
842 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
843 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
844 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
845 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
846 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
847 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
848 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
849 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
850 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
851 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
852 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
853 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
854 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
855 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
856 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
857 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
860 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
861 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
864 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
865 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
866 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
867 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
868 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
869 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
872 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
873 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
874 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
875 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
876 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
877 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
878 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
879 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
880 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
881 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
882 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
883 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
885 // multiplayer missions
888 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
922 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
933 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
936 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
942 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
943 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
944 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
945 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
950 // Internal function prototypes
951 void game_maybe_draw_mouse(float frametime);
952 void init_animating_pointer();
953 void load_animating_pointer(char *filename, int dx, int dy);
954 void unload_animating_pointer();
955 void game_do_training_checks();
956 void game_shutdown(void);
957 void game_show_event_debug(float frametime);
958 void game_event_debug_init();
960 void demo_upsell_show_screens();
961 void game_start_subspace_ambient_sound();
962 void game_stop_subspace_ambient_sound();
963 void verify_ships_tbl();
964 void verify_weapons_tbl();
965 void display_title_screen();
967 // loading background filenames
968 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
969 "LoadingBG", // GR_640
970 "2_LoadingBG" // GR_1024
974 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
975 "Loading.ani", // GR_640
976 "2_Loading.ani" // GR_1024
979 #if defined(FS2_DEMO)
980 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
984 #elif defined(OEM_BUILD)
985 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
992 char Game_CDROM_dir[MAX_PATH_LEN];
995 // How much RAM is on this machine. Set in WinMain
996 uint Freespace_total_ram = 0;
999 float Game_flash_red = 0.0f;
1000 float Game_flash_green = 0.0f;
1001 float Game_flash_blue = 0.0f;
1002 float Sun_spot = 0.0f;
1003 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1005 // game shudder stuff (in ms)
1006 int Game_shudder_time = -1;
1007 int Game_shudder_total = 0;
1008 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1011 sound_env Game_sound_env;
1012 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1013 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1015 int Game_sound_env_update_timestamp;
1017 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1020 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1022 fs_builtin_mission *game_find_builtin_mission(char *filename)
1026 // look through all existing builtin missions
1027 for(idx=0; idx<Game_builtin_mission_count; idx++){
1028 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1029 return &Game_builtin_mission_list[idx];
1037 int game_get_default_skill_level()
1039 return DEFAULT_SKILL_LEVEL;
1043 void game_flash_reset()
1045 Game_flash_red = 0.0f;
1046 Game_flash_green = 0.0f;
1047 Game_flash_blue = 0.0f;
1049 Big_expl_flash.max_flash_intensity = 0.0f;
1050 Big_expl_flash.cur_flash_intensity = 0.0f;
1051 Big_expl_flash.flash_start = 0;
1054 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1055 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1057 void game_framerate_check_init()
1059 // zero critical time
1060 Gf_critical_time = 0.0f;
1063 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1064 // if this is a glide card
1065 if(gr_screen.mode == GR_GLIDE){
1067 extern GrHwConfiguration hwconfig;
1070 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1071 Gf_critical = 15.0f;
1075 Gf_critical = 10.0f;
1080 Gf_critical = 15.0f;
1083 // d3d. only care about good cards here I guess (TNT)
1085 Gf_critical = 15.0f;
1088 // if this is a glide card
1089 if(gr_screen.mode == GR_GLIDE){
1091 extern GrHwConfiguration hwconfig;
1094 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1095 Gf_critical = 25.0f;
1099 Gf_critical = 20.0f;
1104 Gf_critical = 25.0f;
1107 // d3d. only care about good cards here I guess (TNT)
1109 Gf_critical = 25.0f;
1114 extern float Framerate;
1115 void game_framerate_check()
1119 // if the current framerate is above the critical level, add frametime
1120 if(Framerate >= Gf_critical){
1121 Gf_critical_time += flFrametime;
1124 if(!Show_framerate){
1128 // display if we're above the critical framerate
1129 if(Framerate < Gf_critical){
1130 gr_set_color_fast(&Color_bright_red);
1131 gr_string(200, y_start, "Framerate warning");
1136 // display our current pct of good frametime
1137 if(f2fl(Missiontime) >= 0.0f){
1138 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1141 gr_set_color_fast(&Color_bright_green);
1143 gr_set_color_fast(&Color_bright_red);
1146 gr_printf(200, y_start, "%d%%", (int)pct);
1153 // Adds a flash effect. These can be positive or negative.
1154 // The range will get capped at around -1 to 1, so stick
1155 // with a range like that.
1156 void game_flash( float r, float g, float b )
1158 Game_flash_red += r;
1159 Game_flash_green += g;
1160 Game_flash_blue += b;
1162 if ( Game_flash_red < -1.0f ) {
1163 Game_flash_red = -1.0f;
1164 } else if ( Game_flash_red > 1.0f ) {
1165 Game_flash_red = 1.0f;
1168 if ( Game_flash_green < -1.0f ) {
1169 Game_flash_green = -1.0f;
1170 } else if ( Game_flash_green > 1.0f ) {
1171 Game_flash_green = 1.0f;
1174 if ( Game_flash_blue < -1.0f ) {
1175 Game_flash_blue = -1.0f;
1176 } else if ( Game_flash_blue > 1.0f ) {
1177 Game_flash_blue = 1.0f;
1182 // Adds a flash for Big Ship explosions
1183 // cap range from 0 to 1
1184 void big_explosion_flash(float flash)
1186 Big_expl_flash.flash_start = timestamp(1);
1190 } else if (flash < 0.0f) {
1194 Big_expl_flash.max_flash_intensity = flash;
1195 Big_expl_flash.cur_flash_intensity = 0.0f;
1198 // Amount to diminish palette towards normal, per second.
1199 #define DIMINISH_RATE 0.75f
1200 #define SUN_DIMINISH_RATE 6.00f
1204 float sn_glare_scale = 1.7f;
1207 dc_get_arg(ARG_FLOAT);
1208 sn_glare_scale = Dc_arg_float;
1211 float Supernova_last_glare = 0.0f;
1212 void game_sunspot_process(float frametime)
1216 float Sun_spot_goal = 0.0f;
1219 sn_stage = supernova_active();
1221 // sunspot differently based on supernova stage
1223 // approaching. player still in control
1226 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1229 light_get_global_dir(&light_dir, 0);
1231 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1234 // scale it some more
1235 dot = dot * (0.5f + (pct * 0.5f));
1238 Sun_spot_goal += (dot * sn_glare_scale);
1241 // draw the sun glow
1242 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1243 // draw the glow for this sun
1244 stars_draw_sun_glow(0);
1247 Supernova_last_glare = Sun_spot_goal;
1250 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1253 Sun_spot_goal = 0.9f;
1254 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1256 if(Sun_spot_goal > 1.0f){
1257 Sun_spot_goal = 1.0f;
1260 Sun_spot_goal *= sn_glare_scale;
1261 Supernova_last_glare = Sun_spot_goal;
1264 // fade to white. display dead popup
1267 Supernova_last_glare += (2.0f * flFrametime);
1268 if(Supernova_last_glare > 2.0f){
1269 Supernova_last_glare = 2.0f;
1272 Sun_spot_goal = Supernova_last_glare;
1279 // check sunspots for all suns
1280 n_lights = light_get_global_count();
1283 for(idx=0; idx<n_lights; idx++){
1284 //(vector *eye_pos, matrix *eye_orient)
1285 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1288 light_get_global_dir(&light_dir, idx);
1290 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1292 Sun_spot_goal += (float)pow(dot,85.0f);
1294 // draw the glow for this sun
1295 stars_draw_sun_glow(idx);
1297 Sun_spot_goal = 0.0f;
1303 Sun_spot_goal = 0.0f;
1307 float dec_amount = frametime*SUN_DIMINISH_RATE;
1309 if ( Sun_spot < Sun_spot_goal ) {
1310 Sun_spot += dec_amount;
1311 if ( Sun_spot > Sun_spot_goal ) {
1312 Sun_spot = Sun_spot_goal;
1314 } else if ( Sun_spot > Sun_spot_goal ) {
1315 Sun_spot -= dec_amount;
1316 if ( Sun_spot < Sun_spot_goal ) {
1317 Sun_spot = Sun_spot_goal;
1323 // Call once a frame to diminish the
1324 // flash effect to 0.
1325 void game_flash_diminish(float frametime)
1327 float dec_amount = frametime*DIMINISH_RATE;
1329 if ( Game_flash_red > 0.0f ) {
1330 Game_flash_red -= dec_amount;
1331 if ( Game_flash_red < 0.0f )
1332 Game_flash_red = 0.0f;
1334 Game_flash_red += dec_amount;
1335 if ( Game_flash_red > 0.0f )
1336 Game_flash_red = 0.0f;
1339 if ( Game_flash_green > 0.0f ) {
1340 Game_flash_green -= dec_amount;
1341 if ( Game_flash_green < 0.0f )
1342 Game_flash_green = 0.0f;
1344 Game_flash_green += dec_amount;
1345 if ( Game_flash_green > 0.0f )
1346 Game_flash_green = 0.0f;
1349 if ( Game_flash_blue > 0.0f ) {
1350 Game_flash_blue -= dec_amount;
1351 if ( Game_flash_blue < 0.0f )
1352 Game_flash_blue = 0.0f;
1354 Game_flash_blue += dec_amount;
1355 if ( Game_flash_blue > 0.0f )
1356 Game_flash_blue = 0.0f;
1359 // update big_explosion_cur_flash
1360 #define TIME_UP 1500
1361 #define TIME_DOWN 2500
1362 int duration = TIME_UP + TIME_DOWN;
1363 int time = timestamp_until(Big_expl_flash.flash_start);
1364 if (time > -duration) {
1366 if (time < TIME_UP) {
1367 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1370 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1374 if ( Use_palette_flash ) {
1376 // static int or=0, og=0, ob=0;
1378 // Change the 200 to change the color range of colors.
1379 r = fl2i( Game_flash_red*128.0f );
1380 g = fl2i( Game_flash_green*128.0f );
1381 b = fl2i( Game_flash_blue*128.0f );
1383 if ( Sun_spot > 0.0f ) {
1384 r += fl2i(Sun_spot*128.0f);
1385 g += fl2i(Sun_spot*128.0f);
1386 b += fl2i(Sun_spot*128.0f);
1389 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1390 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1391 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1392 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1395 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1396 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1397 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1399 if ( (r!=0) || (g!=0) || (b!=0) ) {
1400 gr_flash( r, g, b );
1402 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1413 void game_level_close()
1415 // De-Initialize the game subsystems
1416 message_mission_shutdown();
1417 event_music_level_close();
1418 game_stop_looped_sounds();
1420 obj_snd_level_close(); // uninit object-linked persistant sounds
1421 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1422 anim_level_close(); // stop and clean up any anim instances
1423 shockwave_level_close();
1424 fireball_level_close();
1426 mission_event_shutdown();
1427 asteroid_level_close();
1428 model_cache_reset(); // Reset/free all the model caching stuff
1429 flak_level_close(); // unload flak stuff
1430 neb2_level_close(); // shutdown gaseous nebula stuff
1433 mflash_level_close();
1435 audiostream_unpause_all();
1440 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1441 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1442 void game_level_init(int seed)
1444 // seed the random number generator
1446 // if no seed was passed, seed the generator either from the time value, or from the
1447 // netgame security flags -- ensures that all players in multiplayer game will have the
1448 // same randon number sequence (with static rand functions)
1449 if ( Game_mode & GM_NORMAL ) {
1450 Game_level_seed = time(NULL);
1452 Game_level_seed = Netgame.security;
1455 // mwa 9/17/98 -- maybe this assert isn't needed????
1456 Assert( !(Game_mode & GM_MULTIPLAYER) );
1457 Game_level_seed = seed;
1459 srand( Game_level_seed );
1461 // semirand function needs to get re-initted every time in multiplayer
1462 if ( Game_mode & GM_MULTIPLAYER ){
1468 Key_normal_game = (Game_mode & GM_NORMAL);
1471 Game_shudder_time = -1;
1473 // Initialize the game subsystems
1474 // timestamp_reset(); // Must be inited before everything else
1476 game_reset_time(); // resets time, and resets saved time too
1478 obj_init(); // Must be inited before the other systems
1479 model_free_all(); // Free all existing models
1480 mission_brief_common_init(); // Free all existing briefing/debriefing text
1481 weapon_level_init();
1482 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1484 player_level_init();
1485 shipfx_flash_init(); // Init the ship gun flash system.
1486 game_flash_reset(); // Reset the flash effect
1487 particle_init(); // Reset the particle system
1491 shield_hit_init(); // Initialize system for showing shield hits
1492 radar_mission_init();
1493 mission_init_goals();
1496 obj_snd_level_init(); // init object-linked persistant sounds
1498 shockwave_level_init();
1499 afterburner_level_init();
1500 scoring_level_init( &Player->stats );
1502 asteroid_level_init();
1503 control_config_clear_used_status();
1504 collide_ship_ship_sounds_init();
1506 Pre_player_entry = 1; // Means the player has not yet entered.
1507 Entry_delay_time = 0; // Could get overwritten in mission read.
1508 fireball_preload(); // page in warphole bitmaps
1510 flak_level_init(); // initialize flak - bitmaps, etc
1511 ct_level_init(); // initialize ships contrails, etc
1512 awacs_level_init(); // initialize AWACS
1513 beam_level_init(); // initialize beam weapons
1514 mflash_level_init();
1516 supernova_level_init();
1518 // multiplayer dogfight hack
1521 shipfx_engine_wash_level_init();
1525 Last_view_target = NULL;
1530 // campaign wasn't ended
1531 Campaign_ended_in_mission = 0;
1534 // called when a mission is over -- does server specific stuff.
1535 void freespace_stop_mission()
1538 Game_mode &= ~GM_IN_MISSION;
1541 // called at frame interval to process networking stuff
1542 void game_do_networking()
1544 Assert( Net_player != NULL );
1545 if (!(Game_mode & GM_MULTIPLAYER)){
1549 // see if this player should be reading/writing data. Bit is set when at join
1550 // screen onward until quits back to main menu.
1551 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1555 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1558 multi_pause_do_frame();
1563 // Loads the best palette for this level, based
1564 // on nebula color and hud color. You could just call palette_load_table with
1565 // the appropriate filename, but who wants to do that.
1566 void game_load_palette()
1568 char palette_filename[1024];
1570 // We only use 3 hud colors right now
1571 // Assert( HUD_config.color >= 0 );
1572 // Assert( HUD_config.color <= 2 );
1574 Assert( Mission_palette >= 0 );
1575 Assert( Mission_palette <= 98 );
1577 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1578 strcpy( palette_filename, NOX("gamepalette-subspace") );
1580 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1583 mprintf(( "Loading palette %s\n", palette_filename ));
1585 // palette_load_table(palette_filename);
1588 void game_post_level_init()
1590 // Stuff which gets called after mission is loaded. Because player isn't created until
1591 // after mission loads, some things must get initted after the level loads
1593 model_level_post_init();
1596 hud_setup_escort_list();
1597 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1603 game_event_debug_init();
1606 training_mission_init();
1607 asteroid_create_all();
1609 game_framerate_check_init();
1613 // An estimate as to how high the count passed to game_loading_callback will go.
1614 // This is just a guess, it seems to always be about the same. The count is
1615 // proportional to the code being executed, not the time, so this works good
1616 // for a bar, assuming the code does about the same thing each time you
1617 // load a level. You can find this value by looking at the return value
1618 // of game_busy_callback(NULL), which I conveniently print out to the
1619 // debug output window with the '=== ENDING LOAD ==' stuff.
1620 //#define COUNT_ESTIMATE 3706
1621 #define COUNT_ESTIMATE 1111
1623 int Game_loading_callback_inited = 0;
1625 int Game_loading_background = -1;
1626 anim * Game_loading_ani = NULL;
1627 anim_instance *Game_loading_ani_instance;
1628 int Game_loading_frame=-1;
1630 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1639 // This gets called 10x per second and count is the number of times
1640 // game_busy() has been called since the current callback function
1642 void game_loading_callback(int count)
1644 game_do_networking();
1646 Assert( Game_loading_callback_inited==1 );
1647 Assert( Game_loading_ani != NULL );
1649 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1650 if ( framenum > Game_loading_ani->total_frames-1 ) {
1651 framenum = Game_loading_ani->total_frames-1;
1652 } else if ( framenum < 0 ) {
1657 while ( Game_loading_frame < framenum ) {
1658 Game_loading_frame++;
1659 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1663 if ( cbitmap > -1 ) {
1664 if ( Game_loading_background > -1 ) {
1665 gr_set_bitmap( Game_loading_background );
1669 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1670 gr_set_bitmap( cbitmap );
1671 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1673 bm_release(cbitmap);
1679 void game_loading_callback_init()
1681 Assert( Game_loading_callback_inited==0 );
1683 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1684 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1687 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1688 Assert( Game_loading_ani != NULL );
1689 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1690 Assert( Game_loading_ani_instance != NULL );
1691 Game_loading_frame = -1;
1693 Game_loading_callback_inited = 1;
1695 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1700 void game_loading_callback_close()
1702 Assert( Game_loading_callback_inited==1 );
1704 // Make sure bar shows all the way over.
1705 game_loading_callback(COUNT_ESTIMATE);
1707 int real_count = game_busy_callback( NULL );
1710 Game_loading_callback_inited = 0;
1713 mprintf(( "=================== ENDING LOAD ================\n" ));
1714 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1715 mprintf(( "================================================\n" ));
1717 // to remove warnings in release build
1721 free_anim_instance(Game_loading_ani_instance);
1722 Game_loading_ani_instance = NULL;
1723 anim_free(Game_loading_ani);
1724 Game_loading_ani = NULL;
1726 bm_release( Game_loading_background );
1727 common_free_interface_palette(); // restore game palette
1728 Game_loading_background = -1;
1730 gr_set_font( FONT1 );
1733 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1735 void game_maybe_update_sound_environment()
1737 // do nothing for now
1740 // Assign the sound environment for the game, based on the current mission
1742 void game_assign_sound_environment()
1745 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1746 Game_sound_env.id = SND_ENV_DRUGGED;
1747 Game_sound_env.volume = 0.800f;
1748 Game_sound_env.damping = 1.188f;
1749 Game_sound_env.decay = 6.392f;
1751 } else if (Num_asteroids > 30) {
1752 Game_sound_env.id = SND_ENV_AUDITORIUM;
1753 Game_sound_env.volume = 0.603f;
1754 Game_sound_env.damping = 0.5f;
1755 Game_sound_env.decay = 4.279f;
1758 Game_sound_env = Game_default_sound_env;
1762 Game_sound_env = Game_default_sound_env;
1763 Game_sound_env_update_timestamp = timestamp(1);
1766 // function which gets called before actually entering the mission. It is broken down into a funciton
1767 // since it will get called in one place from a single player game and from another place for
1768 // a multiplayer game
1769 void freespace_mission_load_stuff()
1771 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1772 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1773 if(!(Game_mode & GM_STANDALONE_SERVER)){
1775 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1777 game_loading_callback_init();
1779 event_music_level_init(); // preloads the first 2 seconds for each event music track
1782 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1785 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1788 ship_assign_sound_all(); // assign engine sounds to ships
1789 game_assign_sound_environment(); // assign the sound environment for this mission
1792 // call function in missionparse.cpp to fixup player/ai stuff.
1793 mission_parse_fixup_players();
1796 // Load in all the bitmaps for this level
1801 game_loading_callback_close();
1803 // the only thing we need to call on the standalone for now.
1805 // call function in missionparse.cpp to fixup player/ai stuff.
1806 mission_parse_fixup_players();
1808 // Load in all the bitmaps for this level
1814 uint load_mission_load;
1815 uint load_post_level_init;
1816 uint load_mission_stuff;
1818 // tells the server to load the mission and initialize structures
1819 int game_start_mission()
1821 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1823 load_gl_init = time(NULL);
1825 load_gl_init = time(NULL) - load_gl_init;
1827 if (Game_mode & GM_MULTIPLAYER) {
1828 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1830 // clear multiplayer stats
1831 init_multiplayer_stats();
1834 load_mission_load = time(NULL);
1835 if (mission_load()) {
1836 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1837 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1838 gameseq_post_event(GS_EVENT_MAIN_MENU);
1840 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1845 load_mission_load = time(NULL) - load_mission_load;
1847 // If this is a red alert mission in campaign mode, bash wingman status
1848 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1849 red_alert_bash_wingman_status();
1852 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1853 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1854 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1855 // game_load_palette();
1858 load_post_level_init = time(NULL);
1859 game_post_level_init();
1860 load_post_level_init = time(NULL) - load_post_level_init;
1864 void Do_model_timings_test();
1865 Do_model_timings_test();
1869 load_mission_stuff = time(NULL);
1870 freespace_mission_load_stuff();
1871 load_mission_stuff = time(NULL) - load_mission_stuff;
1876 int Interface_framerate = 0;
1879 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1880 DCF_BOOL( show_framerate, Show_framerate )
1881 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1882 DCF_BOOL( show_target_weapons, Show_target_weapons )
1883 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1884 DCF_BOOL( sound, Sound_enabled )
1885 DCF_BOOL( zbuffer, game_zbuffer )
1886 DCF_BOOL( shield_system, New_shield_system )
1887 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1888 DCF_BOOL( player_attacking, Player_attacking_enabled )
1889 DCF_BOOL( show_waypoints, Show_waypoints )
1890 DCF_BOOL( show_area_effect, Show_area_effect )
1891 DCF_BOOL( show_net_stats, Show_net_stats )
1892 DCF_BOOL( log, Log_debug_output_to_file )
1893 DCF_BOOL( training_msg_method, Training_msg_method )
1894 DCF_BOOL( show_player_pos, Show_player_pos )
1895 DCF_BOOL(i_framerate, Interface_framerate )
1897 DCF(show_mem,"Toggles showing mem usage")
1900 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1901 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1902 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1903 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1909 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1911 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1912 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1916 DCF(show_cpu,"Toggles showing cpu usage")
1919 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1920 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1921 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1922 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1928 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1930 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1931 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1938 // AL 4-8-98: always allow players to display their framerate
1941 DCF_BOOL( show_framerate, Show_framerate )
1948 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1951 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1952 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1953 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1954 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1956 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" );
1957 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1959 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1962 DCF(palette_flash,"Toggles palette flash effect on/off")
1965 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1966 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1967 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1968 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1970 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1971 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1974 int Use_low_mem = 0;
1976 DCF(low_mem,"Uses low memory settings regardless of RAM")
1979 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1980 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1981 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1982 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1984 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1985 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1987 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1993 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1996 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1997 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1998 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1999 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2001 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2002 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2003 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2007 int Framerate_delay = 0;
2009 float Freespace_gamma = 1.0f;
2011 DCF(gamma,"Sets Gamma factor")
2014 dc_get_arg(ARG_FLOAT|ARG_NONE);
2015 if ( Dc_arg_type & ARG_FLOAT ) {
2016 Freespace_gamma = Dc_arg_float;
2018 dc_printf( "Gamma reset to 1.0f\n" );
2019 Freespace_gamma = 1.0f;
2021 if ( Freespace_gamma < 0.1f ) {
2022 Freespace_gamma = 0.1f;
2023 } else if ( Freespace_gamma > 5.0f ) {
2024 Freespace_gamma = 5.0f;
2026 gr_set_gamma(Freespace_gamma);
2028 char tmp_gamma_string[32];
2029 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2030 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2034 dc_printf( "Usage: gamma <float>\n" );
2035 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2036 Dc_status = 0; // don't print status if help is printed. Too messy.
2040 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2049 Game_current_mission_filename[0] = 0;
2051 // seed the random number generator
2052 Game_init_seed = time(NULL);
2053 srand( Game_init_seed );
2055 Framerate_delay = 0;
2061 extern void bm_init();
2067 // Initialize the timer before the os
2075 GetCurrentDirectory(1024, whee);
2078 getcwd (whee, 1024);
2081 strcat(whee, EXE_FNAME);
2083 //Initialize the libraries
2084 s1 = timer_get_milliseconds();
2085 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2088 e1 = timer_get_milliseconds();
2090 // time a bunch of cfopens
2092 s2 = timer_get_milliseconds();
2094 for(int idx=0; idx<10000; idx++){
2095 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2100 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2102 e2 = timer_get_milliseconds();
2105 if (Is_standalone) {
2106 std_init_standalone();
2108 os_init( Osreg_class_name, Osreg_app_name );
2109 os_set_title(Osreg_title);
2112 // initialize localization module. Make sure this is down AFTER initialzing OS.
2113 // int t1 = timer_get_milliseconds();
2116 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2118 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2121 // verify that he has a valid weapons.tbl
2122 verify_weapons_tbl();
2124 // Output version numbers to registry for auto patching purposes
2125 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2126 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2127 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2129 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2130 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2131 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2134 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2138 Asteroids_enabled = 1;
2141 /////////////////////////////
2143 /////////////////////////////
2148 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2149 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2151 if (!stricmp(ptr, NOX("no sound"))) {
2152 Cmdline_freespace_no_sound = 1;
2154 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2156 } else if (!stricmp(ptr, NOX("EAX"))) {
2161 if (!Is_standalone) {
2162 snd_init(use_a3d, use_eax);
2164 /////////////////////////////
2166 /////////////////////////////
2168 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2171 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);
2173 // fire up the UpdateLauncher executable
2175 PROCESS_INFORMATION pi;
2177 memset( &si, 0, sizeof(STARTUPINFO) );
2180 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2181 NULL, // pointer to command line string
2182 NULL, // pointer to process security attributes
2183 NULL, // pointer to thread security attributes
2184 FALSE, // handle inheritance flag
2185 CREATE_DEFAULT_ERROR_MODE, // creation flags
2186 NULL, // pointer to new environment block
2187 NULL, // pointer to current directory name
2188 &si, // pointer to STARTUPINFO
2189 &pi // pointer to PROCESS_INFORMATION
2192 // If the Launcher could not be started up, let the user know
2194 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2203 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2205 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);
2213 // check for hi res pack file
2214 int has_sparky_hi = 0;
2216 // check if sparky_hi exists -- access mode 0 means does file exist
2219 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2222 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2225 // see if we've got 32 bit in the string
2226 if(strstr(ptr, "32 bit")){
2233 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2235 // always 640 for E3
2236 gr_init(GR_640, GR_GLIDE);
2238 // regular or hi-res ?
2240 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2242 if(strstr(ptr, NOX("(1024x768)"))){
2244 gr_init(GR_1024, GR_GLIDE);
2246 gr_init(GR_640, GR_GLIDE);
2249 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2251 // always 640 for E3
2253 gr_init(GR_640, GR_DIRECT3D, depth);
2255 // regular or hi-res ?
2257 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2259 if(strstr(ptr, NOX("(1024x768)"))){
2263 gr_init(GR_1024, GR_DIRECT3D, depth);
2267 gr_init(GR_640, GR_DIRECT3D, depth);
2273 if ( Use_fullscreen_at_startup && !Is_standalone) {
2274 gr_init(GR_640, GR_DIRECTDRAW);
2276 gr_init(GR_640, GR_SOFTWARE);
2279 if ( !Is_standalone ) {
2280 gr_init(GR_640, GR_DIRECTDRAW);
2282 gr_init(GR_640, GR_SOFTWARE);
2287 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2288 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2289 gr_init(GR_1024, GR_OPENGL);
2291 gr_init(GR_640, GR_OPENGL);
2295 gr_init(GR_640, GR_SOFTWARE);
2300 extern int Gr_inited;
2301 if(trying_d3d && !Gr_inited){
2303 extern char Device_init_error[512];
2304 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2313 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2314 Freespace_gamma = (float)atof(ptr);
2315 if ( Freespace_gamma == 0.0f ) {
2316 Freespace_gamma = 1.80f;
2317 } else if ( Freespace_gamma < 0.1f ) {
2318 Freespace_gamma = 0.1f;
2319 } else if ( Freespace_gamma > 5.0f ) {
2320 Freespace_gamma = 5.0f;
2322 char tmp_gamma_string[32];
2323 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2324 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2326 gr_set_gamma(Freespace_gamma);
2328 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2331 display_title_screen();
2335 // attempt to load up master tracker registry info (login and password)
2336 Multi_tracker_id = -1;
2338 // pxo login and password
2339 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2341 nprintf(("Network","Error reading in PXO login data\n"));
2342 strcpy(Multi_tracker_login,"");
2344 strcpy(Multi_tracker_login,ptr);
2346 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2348 nprintf(("Network","Error reading PXO password\n"));
2349 strcpy(Multi_tracker_passwd,"");
2351 strcpy(Multi_tracker_passwd,ptr);
2354 // pxo squad name and password
2355 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2357 nprintf(("Network","Error reading in PXO squad name\n"));
2358 strcpy(Multi_tracker_squad_name, "");
2360 strcpy(Multi_tracker_squad_name, ptr);
2363 // If less than 48MB of RAM, use low memory model.
2364 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2365 mprintf(( "Using normal memory settings...\n" ));
2366 bm_set_low_mem(1); // Use every other frame of bitmaps
2368 mprintf(( "Using high memory settings...\n" ));
2369 bm_set_low_mem(0); // Use all frames of bitmaps
2372 // load non-darkening pixel defs
2373 palman_load_pixels();
2375 // hud shield icon stuff
2376 hud_shield_game_init();
2378 control_config_common_init(); // sets up localization stuff in the control config
2384 gamesnd_parse_soundstbl();
2389 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2394 player_controls_init();
2397 //if(!Is_standalone){
2405 ship_init(); // read in ships.tbl
2407 mission_campaign_init(); // load in the default campaign
2409 // navmap_init(); // init the navigation map system
2410 context_help_init();
2411 techroom_intel_init(); // parse species.tbl, load intel info
2413 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2414 init_animating_pointer();
2416 mission_brief_common_init(); // Mark all the briefing structures as empty.
2417 gr_font_init(); // loads up all fonts
2419 neb2_init(); // fullneb stuff
2423 player_tips_init(); // helpful tips
2426 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2427 pilot_load_pic_list();
2428 pilot_load_squad_pic_list();
2430 load_animating_pointer(NOX("cursor"), 0, 0);
2432 // initialize alpha colors
2433 alpha_colors_init();
2436 // Game_music_paused = 0;
2443 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2444 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2446 mprintf(("cfile_init() took %d\n", e1 - s1));
2447 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2450 char transfer_text[128];
2452 float Start_time = 0.0f;
2454 float Framerate = 0.0f;
2456 float Timing_total = 0.0f;
2457 float Timing_render2 = 0.0f;
2458 float Timing_render3 = 0.0f;
2459 float Timing_flip = 0.0f;
2460 float Timing_clear = 0.0f;
2462 MONITOR(NumPolysDrawn);
2468 void game_get_framerate()
2470 char text[128] = "";
2472 if ( frame_int == -1 ) {
2474 for (i=0; i<FRAME_FILTER; i++ ) {
2475 frametimes[i] = 0.0f;
2480 frametotal -= frametimes[frame_int];
2481 frametotal += flFrametime;
2482 frametimes[frame_int] = flFrametime;
2483 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2485 if ( frametotal != 0.0 ) {
2486 if ( Framecount >= FRAME_FILTER )
2487 Framerate = FRAME_FILTER / frametotal;
2489 Framerate = Framecount / frametotal;
2490 sprintf( text, NOX("FPS: %.1f"), Framerate );
2492 sprintf( text, NOX("FPS: ?") );
2496 if (Show_framerate) {
2497 gr_set_color_fast(&HUD_color_debug);
2498 gr_string( 570, 2, text );
2502 void game_show_framerate()
2506 cur_time = f2fl(timer_get_approx_seconds());
2507 if (cur_time - Start_time > 30.0f) {
2508 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2509 Start_time += 1000.0f;
2512 //mprintf(( "%s\n", text ));
2515 if ( Debug_dump_frames )
2519 // possibly show control checking info
2520 control_check_indicate();
2522 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2523 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2524 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2525 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2528 if ( Show_cpu == 1 ) {
2533 dy = gr_get_font_height() + 1;
2535 gr_set_color_fast(&HUD_color_debug);
2539 extern int D3D_textures_in;
2540 extern int D3D_textures_in_frame;
2541 extern int Glide_textures_in;
2542 extern int Glide_textures_in_frame;
2543 extern int Glide_explosion_vram;
2544 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2546 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2548 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2554 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2556 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2558 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2560 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2562 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2567 extern int Num_pairs; // Number of object pairs that were checked.
2568 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2571 extern int Num_pairs_checked; // What percent of object pairs were checked.
2572 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2574 Num_pairs_checked = 0;
2578 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2581 if ( Timing_total > 0.01f ) {
2582 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2584 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2586 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2588 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2590 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2600 dy = gr_get_font_height() + 1;
2602 gr_set_color_fast(&HUD_color_debug);
2605 extern int TotalRam;
2606 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2611 extern int Model_ram;
2612 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2616 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2618 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2620 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2624 extern int D3D_textures_in;
2625 extern int Glide_textures_in;
2626 extern int Glide_textures_in_frame;
2627 extern int Glide_explosion_vram;
2628 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2630 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2632 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2641 if ( Show_player_pos ) {
2645 gr_printf(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.x), fl2i(Player_obj->pos.y), fl2i(Player_obj->pos.z));
2648 MONITOR_INC(NumPolys, modelstats_num_polys);
2649 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2650 MONITOR_INC(NumVerts, modelstats_num_verts );
2652 modelstats_num_polys = 0;
2653 modelstats_num_polys_drawn = 0;
2654 modelstats_num_verts = 0;
2655 modelstats_num_sortnorms = 0;
2659 void game_show_standalone_framerate()
2661 float frame_rate=30.0f;
2662 if ( frame_int == -1 ) {
2664 for (i=0; i<FRAME_FILTER; i++ ) {
2665 frametimes[i] = 0.0f;
2670 frametotal -= frametimes[frame_int];
2671 frametotal += flFrametime;
2672 frametimes[frame_int] = flFrametime;
2673 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2675 if ( frametotal != 0.0 ) {
2676 if ( Framecount >= FRAME_FILTER ){
2677 frame_rate = FRAME_FILTER / frametotal;
2679 frame_rate = Framecount / frametotal;
2682 std_set_standalone_fps(frame_rate);
2686 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2687 void game_show_time_left()
2691 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2692 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2693 // checking how much time is left
2695 if ( Mission_end_time == -1 ){
2699 diff = f2i(Mission_end_time - Missiontime);
2700 // be sure to bash to 0. diff could be negative on frame that we quit mission
2705 hud_set_default_color();
2706 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2709 //========================================================================================
2710 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2711 //========================================================================================
2715 DCF(ai_pause,"Pauses ai")
2718 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2719 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2720 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2721 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2724 obj_init_all_ships_physics();
2727 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2728 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2731 DCF(single_step,"Single steps the game")
2734 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2735 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2736 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2737 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2739 last_single_step = 0; // Make so single step waits a frame before stepping
2742 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2743 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2746 DCF_BOOL(physics_pause, physics_paused)
2747 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2748 DCF_BOOL(ai_firing, Ai_firing_enabled )
2750 // Create some simple aliases to these commands...
2751 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2752 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2753 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2754 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2755 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2758 //========================================================================================
2759 //========================================================================================
2762 void game_training_pause_do()
2766 key = game_check_key();
2768 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2775 void game_increase_skill_level()
2778 if (Game_skill_level >= NUM_SKILL_LEVELS){
2779 Game_skill_level = 0;
2783 int Player_died_time;
2785 int View_percent = 100;
2788 DCF(view, "Sets the percent of the 3d view to render.")
2791 dc_get_arg(ARG_INT);
2792 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2793 View_percent = Dc_arg_int;
2795 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2801 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2805 dc_printf("View is set to %d%%\n", View_percent );
2810 // Set the clip region for the 3d rendering window
2811 void game_set_view_clip()
2813 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2814 // Set the clip region for the letterbox "dead view"
2815 int yborder = gr_screen.max_h/4;
2817 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2818 // J.S. I've changed my ways!! See the new "no constants" code!!!
2819 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2821 // Set the clip region for normal view
2822 if ( View_percent >= 100 ) {
2825 int xborder, yborder;
2827 if ( View_percent < 5 ) {
2831 float fp = i2fl(View_percent)/100.0f;
2832 int fi = fl2i(fl_sqrt(fp)*100.0f);
2833 if ( fi > 100 ) fi=100;
2835 xborder = ( gr_screen.max_w*(100-fi) )/200;
2836 yborder = ( gr_screen.max_h*(100-fi) )/200;
2838 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2844 void show_debug_stuff()
2847 int laser_count = 0, missile_count = 0;
2849 for (i=0; i<MAX_OBJECTS; i++) {
2850 if (Objects[i].type == OBJ_WEAPON){
2851 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2853 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2859 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2862 extern int Tool_enabled;
2867 int tst_bitmap = -1;
2869 float tst_offset, tst_offset_total;
2872 void game_tst_frame_pre()
2880 g3_rotate_vertex(&v, &tst_pos);
2881 g3_project_vertex(&v);
2884 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2888 // big ship? always tst
2890 // within 3000 meters
2891 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2895 // within 300 meters
2896 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2903 void game_tst_frame()
2913 tst_time = time(NULL);
2915 // load the tst bitmap
2916 switch((int)frand_range(0.0f, 3.0)){
2918 tst_bitmap = bm_load("ig_jim");
2920 mprintf(("TST 0\n"));
2924 tst_bitmap = bm_load("ig_kan");
2926 mprintf(("TST 1\n"));
2930 tst_bitmap = bm_load("ig_jim");
2932 mprintf(("TST 2\n"));
2936 tst_bitmap = bm_load("ig_kan");
2938 mprintf(("TST 3\n"));
2947 // get the tst bitmap dimensions
2949 bm_get_info(tst_bitmap, &w, &h);
2952 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2954 snd_play(&Snds[SND_VASUDAN_BUP]);
2956 // tst x and direction
2960 tst_offset_total = (float)w;
2961 tst_offset = (float)w;
2963 tst_x = (float)gr_screen.max_w;
2964 tst_offset_total = (float)-w;
2965 tst_offset = (float)w;
2973 float diff = (tst_offset_total / 0.5f) * flFrametime;
2979 tst_offset -= fl_abs(diff);
2980 } else if(tst_mode == 2){
2983 tst_offset -= fl_abs(diff);
2987 gr_set_bitmap(tst_bitmap);
2988 gr_bitmap((int)tst_x, (int)tst_y);
2991 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2995 // if we passed the switch point
2996 if(tst_offset <= 0.0f){
3001 tst_stamp = timestamp(1000);
3002 tst_offset = fl_abs(tst_offset_total);
3013 void game_tst_mark(object *objp, ship *shipp)
3022 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3025 sip = &Ship_info[shipp->ship_info_index];
3032 tst_pos = objp->pos;
3033 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3039 extern void render_shields();
3041 void player_repair_frame(float frametime)
3043 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3045 for(idx=0;idx<MAX_PLAYERS;idx++){
3048 np = &Net_players[idx];
3050 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)){
3052 // don't rearm/repair if the player is dead or dying/departing
3053 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3054 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3059 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3060 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3066 #define NUM_FRAMES_TEST 300
3067 #define NUM_MIXED_SOUNDS 16
3068 void do_timing_test(float flFrametime)
3070 static int framecount = 0;
3071 static int test_running = 0;
3072 static float test_time = 0.0f;
3074 static int snds[NUM_MIXED_SOUNDS];
3077 if ( test_running ) {
3079 test_time += flFrametime;
3080 if ( framecount >= NUM_FRAMES_TEST ) {
3082 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3083 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3088 if ( Test_begin == 1 ) {
3094 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3097 // start looping digital sounds
3098 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3099 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3106 DCF(dcf_fov, "Change the field of view")
3109 dc_get_arg(ARG_FLOAT|ARG_NONE);
3110 if ( Dc_arg_type & ARG_NONE ) {
3111 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3112 dc_printf( "Zoom factor reset\n" );
3114 if ( Dc_arg_type & ARG_FLOAT ) {
3115 if (Dc_arg_float < 0.25f) {
3116 Viewer_zoom = 0.25f;
3117 dc_printf("Zoom factor pinned at 0.25.\n");
3118 } else if (Dc_arg_float > 1.25f) {
3119 Viewer_zoom = 1.25f;
3120 dc_printf("Zoom factor pinned at 1.25.\n");
3122 Viewer_zoom = Dc_arg_float;
3128 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3131 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3135 DCF(framerate_cap, "Sets the framerate cap")
3138 dc_get_arg(ARG_INT);
3139 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3140 Framerate_cap = Dc_arg_int;
3142 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3148 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3149 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3150 dc_printf("[n] must be from 1 to 120.\n");
3154 if ( Framerate_cap )
3155 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3157 dc_printf("There is no framerate cap currently active.\n");
3161 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3162 int Show_viewing_from_self = 0;
3164 void say_view_target()
3166 object *view_target;
3168 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3169 view_target = &Objects[Player_ai->target_objnum];
3171 view_target = Player_obj;
3173 if (Game_mode & GM_DEAD) {
3174 if (Player_ai->target_objnum != -1)
3175 view_target = &Objects[Player_ai->target_objnum];
3178 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3179 if (view_target != Player_obj){
3181 char *view_target_name = NULL;
3182 switch(Objects[Player_ai->target_objnum].type) {
3184 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3187 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3188 Viewer_mode &= ~VM_OTHER_SHIP;
3190 case OBJ_JUMP_NODE: {
3191 char jump_node_name[128];
3192 strcpy(jump_node_name, XSTR( "jump node", 184));
3193 view_target_name = jump_node_name;
3194 Viewer_mode &= ~VM_OTHER_SHIP;
3203 if ( view_target_name ) {
3204 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3205 Show_viewing_from_self = 1;
3208 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3209 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3210 Show_viewing_from_self = 1;
3212 if (Show_viewing_from_self)
3213 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3218 Last_view_target = view_target;
3222 float Game_hit_x = 0.0f;
3223 float Game_hit_y = 0.0f;
3225 // Reset at the beginning of each frame
3226 void game_whack_reset()
3232 // Apply a 2d whack to the player
3233 void game_whack_apply( float x, float y )
3235 // Do some force feedback
3236 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3242 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3245 // call to apply a "shudder"
3246 void game_shudder_apply(int time, float intensity)
3248 Game_shudder_time = timestamp(time);
3249 Game_shudder_total = time;
3250 Game_shudder_intensity = intensity;
3253 #define FF_SCALE 10000
3254 void apply_hud_shake(matrix *eye_orient)
3256 if (Viewer_obj == Player_obj) {
3257 physics_info *pi = &Player_obj->phys_info;
3265 // Make eye shake due to afterburner
3266 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3269 dtime = timestamp_until(pi->afterburner_decay);
3273 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3274 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3277 // Make eye shake due to engine wash
3279 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3282 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3283 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3285 // get the intensity
3286 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3290 vm_vec_rand_vec_quick(&rand_vec);
3293 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3297 // make hud shake due to shuddering
3298 if(Game_shudder_time != -1){
3299 // if the timestamp has elapsed
3300 if(timestamp_elapsed(Game_shudder_time)){
3301 Game_shudder_time = -1;
3303 // otherwise apply some shudder
3307 dtime = timestamp_until(Game_shudder_time);
3311 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));
3312 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));
3317 vm_angles_2_matrix(&tm, &tangles);
3318 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3319 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3320 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3321 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3326 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3328 // Player's velocity just before he blew up. Used to keep camera target moving.
3329 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3331 // Set eye_pos and eye_orient based on view mode.
3332 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3336 static int last_Viewer_mode = 0;
3337 static int last_Game_mode = 0;
3338 static int last_Viewer_objnum = -1;
3340 // This code is supposed to detect camera "cuts"... like going between
3343 // determine if we need to regenerate the nebula
3344 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3345 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3346 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3347 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3348 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3349 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3350 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3351 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3352 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3355 // regenerate the nebula
3359 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3360 //mprintf(( "************** Camera cut! ************\n" ));
3361 last_Viewer_mode = Viewer_mode;
3362 last_Game_mode = Game_mode;
3364 // Camera moved. Tell stars & debris to not do blurring.
3370 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3371 player_display_packlock_view();
3374 game_set_view_clip();
3376 if (Game_mode & GM_DEAD) {
3377 vector vec_to_deader, view_pos;
3380 Viewer_mode |= VM_DEAD_VIEW;
3382 if (Player_ai->target_objnum != -1) {
3383 int view_from_player = 1;
3385 if (Viewer_mode & VM_OTHER_SHIP) {
3386 // View from target.
3387 Viewer_obj = &Objects[Player_ai->target_objnum];
3389 last_Viewer_objnum = Player_ai->target_objnum;
3391 if ( Viewer_obj->type == OBJ_SHIP ) {
3392 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3393 view_from_player = 0;
3396 last_Viewer_objnum = -1;
3399 if ( view_from_player ) {
3400 // View target from player ship.
3402 *eye_pos = Player_obj->pos;
3403 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3404 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3407 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3409 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3410 dist += flFrametime * 16.0f;
3412 vm_vec_scale(&vec_to_deader, -dist);
3413 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3415 view_pos = Player_obj->pos;
3417 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3418 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3419 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3420 Dead_player_last_vel = Player_obj->phys_info.vel;
3421 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.x, Player_obj->phys_info.vel.y, Player_obj->phys_info.vel.z));
3422 } else if (Player_ai->target_objnum != -1) {
3423 view_pos = Objects[Player_ai->target_objnum].pos;
3425 // Make camera follow explosion, but gradually slow down.
3426 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3427 view_pos = Player_obj->pos;
3428 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3429 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3432 *eye_pos = Dead_camera_pos;
3434 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3436 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3441 // if supernova shockwave
3442 if(supernova_camera_cut()){
3446 // call it dead view
3447 Viewer_mode |= VM_DEAD_VIEW;
3449 // set eye pos and orient
3450 supernova_set_view(eye_pos, eye_orient);
3452 // If already blown up, these other modes can override.
3453 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3454 Viewer_mode &= ~VM_DEAD_VIEW;
3456 Viewer_obj = Player_obj;
3458 if (Viewer_mode & VM_OTHER_SHIP) {
3459 if (Player_ai->target_objnum != -1){
3460 Viewer_obj = &Objects[Player_ai->target_objnum];
3461 last_Viewer_objnum = Player_ai->target_objnum;
3463 Viewer_mode &= ~VM_OTHER_SHIP;
3464 last_Viewer_objnum = -1;
3467 last_Viewer_objnum = -1;
3470 if (Viewer_mode & VM_EXTERNAL) {
3473 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3474 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3476 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3478 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3479 vm_vec_normalize(&eye_dir);
3480 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3483 // Modify the orientation based on head orientation.
3484 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3486 } else if ( Viewer_mode & VM_CHASE ) {
3489 if ( Viewer_obj->phys_info.speed < 0.1 )
3490 move_dir = Viewer_obj->orient.fvec;
3492 move_dir = Viewer_obj->phys_info.vel;
3493 vm_vec_normalize(&move_dir);
3496 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3497 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3498 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3499 vm_vec_normalize(&eye_dir);
3501 // JAS: I added the following code because if you slew up using
3502 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3503 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3504 // call because the up and the forward vector are the same. I fixed
3505 // it by adding in a fraction of the right vector all the time to the
3507 vector tmp_up = Viewer_obj->orient.uvec;
3508 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3510 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3513 // Modify the orientation based on head orientation.
3514 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3515 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3516 *eye_pos = Camera_pos;
3518 ship * shipp = &Ships[Player_obj->instance];
3520 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3521 vm_vec_normalize(&eye_dir);
3522 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3525 // get an eye position based upon the correct type of object
3526 switch(Viewer_obj->type){
3528 // make a call to get the eye point for the player object
3529 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3532 // make a call to get the eye point for the player object
3533 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3539 #ifdef JOHNS_DEBUG_CODE
3540 john_debug_stuff(&eye_pos, &eye_orient);
3546 apply_hud_shake(eye_orient);
3548 // setup neb2 rendering
3549 neb2_render_setup(eye_pos, eye_orient);
3553 extern void ai_debug_render_stuff();
3556 int Game_subspace_effect = 0;
3557 DCF_BOOL( subspace, Game_subspace_effect );
3559 // Does everything needed to render a frame
3560 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3564 g3_start_frame(game_zbuffer);
3565 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3567 // maybe offset the HUD (jitter stuff)
3568 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3569 HUD_set_offsets(Viewer_obj, !dont_offset);
3571 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3572 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3573 // must be done before ships are rendered
3574 if ( MULTIPLAYER_CLIENT ) {
3575 shield_point_multi_setup();
3578 if ( Game_subspace_effect ) {
3579 stars_draw(0,0,0,1);
3581 stars_draw(1,1,1,0);
3584 obj_render_all(obj_render);
3585 beam_render_all(); // render all beam weapons
3586 particle_render_all(); // render particles after everything else.
3587 trail_render_all(); // render missilie trails after everything else.
3588 mflash_render_all(); // render all muzzle flashes
3590 // Why do we not show the shield effect in these modes? Seems ok.
3591 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3595 // render nebula lightning
3598 // render local player nebula
3599 neb2_render_player();
3602 ai_debug_render_stuff();
3605 #ifndef RELEASE_REAL
3606 // game_framerate_check();
3610 extern void snd_spew_debug_info();
3611 snd_spew_debug_info();
3614 //================ END OF 3D RENDERING STUFF ====================
3618 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3619 hud_maybe_clear_head_area();
3620 anim_render_all(0, flFrametime);
3623 extern int Multi_display_netinfo;
3624 if(Multi_display_netinfo){
3625 extern void multi_display_netinfo();
3626 multi_display_netinfo();
3629 game_tst_frame_pre();
3632 do_timing_test(flFrametime);
3636 extern int OO_update_index;
3637 multi_rate_display(OO_update_index, 375, 0);
3642 extern void oo_display();
3649 //#define JOHNS_DEBUG_CODE 1
3651 #ifdef JOHNS_DEBUG_CODE
3652 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3654 //if ( keyd_pressed[KEY_LSHIFT] )
3656 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3658 model_subsystem *turret = tsys->system_info;
3660 if (turret->type == SUBSYSTEM_TURRET ) {
3662 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3664 ship_model_start(tobj);
3666 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3667 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3668 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3670 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3672 ship_model_stop(tobj);
3682 // following function for dumping frames for purposes of building trailers.
3685 // function to toggle state of dumping every frame into PCX when playing the game
3686 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3690 if ( Debug_dump_frames == 0 ) {
3692 Debug_dump_frames = 15;
3693 Debug_dump_trigger = 0;
3694 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3695 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3698 Debug_dump_frames = 0;
3699 Debug_dump_trigger = 0;
3700 gr_dump_frame_stop();
3701 dc_printf( "Frame dumping is now OFF\n" );
3707 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3711 if ( Debug_dump_frames == 0 ) {
3713 Debug_dump_frames = 15;
3714 Debug_dump_trigger = 1;
3715 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3716 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3719 Debug_dump_frames = 0;
3720 Debug_dump_trigger = 0;
3721 gr_dump_frame_stop();
3722 dc_printf( "Frame dumping is now OFF\n" );
3728 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3732 if ( Debug_dump_frames == 0 ) {
3734 Debug_dump_frames = 30;
3735 Debug_dump_trigger = 0;
3736 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3737 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3740 Debug_dump_frames = 0;
3741 Debug_dump_trigger = 0;
3742 gr_dump_frame_stop();
3743 dc_printf( "Frame dumping is now OFF\n" );
3749 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3753 if ( Debug_dump_frames == 0 ) {
3755 Debug_dump_frames = 30;
3756 Debug_dump_trigger = 1;
3757 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3758 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3761 Debug_dump_frames = 0;
3762 Debug_dump_trigger = 0;
3763 gr_dump_frame_stop();
3764 dc_printf( "Triggered frame dumping is now OFF\n" );
3770 void game_maybe_dump_frame()
3772 if ( !Debug_dump_frames ){
3776 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3783 Debug_dump_frame_num++;
3789 extern int Player_dead_state;
3791 // Flip the page and time how long it took.
3792 void game_flip_page_and_time_it()
3796 t1 = timer_get_fixed_seconds();
3798 t2 = timer_get_fixed_seconds();
3800 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3801 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3804 void game_simulation_frame()
3806 // blow ships up in multiplayer dogfight
3807 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){
3808 // blow up all non-player ships
3809 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3812 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3814 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)){
3815 moveup = GET_NEXT(moveup);
3818 shipp = &Ships[Objects[moveup->objnum].instance];
3819 sip = &Ship_info[shipp->ship_info_index];
3821 // only blow up small ships
3822 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3823 // function to simply explode a ship where it is currently at
3824 ship_self_destruct( &Objects[moveup->objnum] );
3827 moveup = GET_NEXT(moveup);
3833 // process AWACS stuff - do this first thing
3836 // single player, set Player hits_this_frame to 0
3837 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3838 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3839 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3843 supernova_process();
3844 if(supernova_active() >= 5){
3848 // fire targeting lasers now so that
3849 // 1 - created this frame
3850 // 2 - collide this frame
3851 // 3 - render this frame
3852 // 4 - ignored and deleted next frame
3853 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3855 ship_process_targeting_lasers();
3857 // do this here so that it works for multiplayer
3859 // get viewer direction
3860 int viewer_direction = PHYSICS_VIEWER_REAR;
3862 if(Viewer_mode == 0){
3863 viewer_direction = PHYSICS_VIEWER_FRONT;
3865 if(Viewer_mode & VM_PADLOCK_UP){
3866 viewer_direction = PHYSICS_VIEWER_UP;
3868 else if(Viewer_mode & VM_PADLOCK_REAR){
3869 viewer_direction = PHYSICS_VIEWER_REAR;
3871 else if(Viewer_mode & VM_PADLOCK_LEFT){
3872 viewer_direction = PHYSICS_VIEWER_LEFT;
3874 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3875 viewer_direction = PHYSICS_VIEWER_RIGHT;
3878 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3880 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3883 #define VM_PADLOCK_UP (1 << 7)
3884 #define VM_PADLOCK_REAR (1 << 8)
3885 #define VM_PADLOCK_LEFT (1 << 9)
3886 #define VM_PADLOCK_RIGHT (1 << 10)
3888 // evaluate mission departures and arrivals before we process all objects.
3889 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3891 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3892 // ships/wing packets.
3893 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3894 mission_parse_eval_stuff();
3897 // if we're an observer, move ourselves seperately from the standard physics
3898 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3899 obj_observer_move(flFrametime);
3902 // move all the objects now
3903 obj_move_all(flFrametime);
3905 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3906 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3907 // ship_check_cargo_all();
3908 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3909 mission_eval_goals();
3913 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3914 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3915 training_check_objectives();
3918 // do all interpolation now
3919 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3920 // client side processing of warping in effect stages
3921 multi_do_client_warp(flFrametime);
3923 // client side movement of an observer
3924 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3925 obj_observer_move(flFrametime);
3928 // move all objects - does interpolation now as well
3929 obj_move_all(flFrametime);
3932 // only process the message queue when the player is "in" the game
3933 if ( !Pre_player_entry ){
3934 message_queue_process(); // process any messages send to the player
3937 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3938 message_maybe_distort(); // maybe distort incoming message if comms damaged
3939 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3940 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3941 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3944 if(!(Game_mode & GM_STANDALONE_SERVER)){
3945 // process some stuff every frame (before frame is rendered)
3946 emp_process_local();
3948 hud_update_frame(); // update hud systems
3950 if (!physics_paused) {
3951 // Move particle system
3952 particle_move_all(flFrametime);
3954 // Move missile trails
3955 trail_move_all(flFrametime);
3957 // process muzzle flashes
3958 mflash_process_all();
3960 // Flash the gun flashes
3961 shipfx_flash_do_frame(flFrametime);
3963 shockwave_move_all(flFrametime); // update all the shockwaves
3966 // subspace missile strikes
3969 obj_snd_do_frame(); // update the object-linked persistant sounds
3970 game_maybe_update_sound_environment();
3971 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3973 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3975 if ( Game_subspace_effect ) {
3976 game_start_subspace_ambient_sound();
3982 // Maybe render and process the dead-popup
3983 void game_maybe_do_dead_popup(float frametime)
3985 if ( popupdead_is_active() ) {
3987 int choice = popupdead_do_frame(frametime);
3989 if ( Game_mode & GM_NORMAL ) {
3993 if(game_do_cd_mission_check(Game_current_mission_filename)){
3994 gameseq_post_event(GS_EVENT_ENTER_GAME);
3996 gameseq_post_event(GS_EVENT_MAIN_MENU);
4001 gameseq_post_event(GS_EVENT_END_GAME);
4006 if(game_do_cd_mission_check(Game_current_mission_filename)){
4007 gameseq_post_event(GS_EVENT_START_GAME);
4009 gameseq_post_event(GS_EVENT_MAIN_MENU);
4013 // this should only happen during a red alert mission
4016 Assert(The_mission.red_alert);
4017 if(!The_mission.red_alert){
4019 if(game_do_cd_mission_check(Game_current_mission_filename)){
4020 gameseq_post_event(GS_EVENT_START_GAME);
4022 gameseq_post_event(GS_EVENT_MAIN_MENU);
4027 // choose the previous mission
4028 mission_campaign_previous_mission();
4030 if(game_do_cd_mission_check(Game_current_mission_filename)){
4031 gameseq_post_event(GS_EVENT_START_GAME);
4033 gameseq_post_event(GS_EVENT_MAIN_MENU);
4044 case POPUPDEAD_DO_MAIN_HALL:
4045 multi_quit_game(PROMPT_NONE,-1);
4048 case POPUPDEAD_DO_RESPAWN:
4049 multi_respawn_normal();
4050 event_music_player_respawn();
4053 case POPUPDEAD_DO_OBSERVER:
4054 multi_respawn_observer();
4055 event_music_player_respawn_as_observer();
4064 if ( leave_popup ) {
4070 // returns true if player is actually in a game_play stats
4071 int game_actually_playing()
4075 state = gameseq_get_state();
4076 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4082 // Draw the 2D HUD gauges
4083 void game_render_hud_2d()
4085 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4089 HUD_render_2d(flFrametime);
4093 // Draw the 3D-dependant HUD gauges
4094 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4096 g3_start_frame(0); // 0 = turn zbuffering off
4097 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4099 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4100 HUD_render_3d(flFrametime);
4104 game_sunspot_process(flFrametime);
4106 // Diminish the palette effect
4107 game_flash_diminish(flFrametime);
4115 int actually_playing;
4116 fix total_time1, total_time2;
4117 fix render2_time1=0, render2_time2=0;
4118 fix render3_time1=0, render3_time2=0;
4119 fix flip_time1=0, flip_time2=0;
4120 fix clear_time1=0, clear_time2=0;
4126 if (Framerate_delay) {
4127 int start_time = timer_get_milliseconds();
4128 while (timer_get_milliseconds() < start_time + Framerate_delay)
4134 demo_do_frame_start();
4136 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4141 // start timing frame
4142 timing_frame_start();
4144 total_time1 = timer_get_fixed_seconds();
4146 // var to hold which state we are in
4147 actually_playing = game_actually_playing();
4149 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4150 if (!(Game_mode & GM_STANDALONE_SERVER)){
4151 Assert( OBJ_INDEX(Player_obj) >= 0 );
4155 if (Missiontime > Entry_delay_time){
4156 Pre_player_entry = 0;
4158 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4161 // Note: These are done even before the player enters, else buffers can overflow.
4162 if (! (Game_mode & GM_STANDALONE_SERVER)){
4166 shield_frame_init();
4168 if ( Player->control_mode != PCM_NORMAL )
4171 if ( !Pre_player_entry && actually_playing ) {
4172 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4174 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4175 game_process_keys();
4177 // don't read flying controls if we're playing a demo back
4178 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4179 read_player_controls( Player_obj, flFrametime);
4183 // if we're not the master, we may have to send the server-critical ship status button_info bits
4184 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4185 multi_maybe_send_ship_status();
4190 // Reset the whack stuff
4193 // These two lines must be outside of Pre_player_entry code,
4194 // otherwise too many lights are added.
4197 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4201 game_simulation_frame();
4203 // if not actually in a game play state, then return. This condition could only be true in
4204 // a multiplayer game.
4205 if ( !actually_playing ) {
4206 Assert( Game_mode & GM_MULTIPLAYER );
4210 if (!Pre_player_entry) {
4211 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4212 clear_time1 = timer_get_fixed_seconds();
4213 // clear the screen to black
4215 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4219 clear_time2 = timer_get_fixed_seconds();
4220 render3_time1 = timer_get_fixed_seconds();
4221 game_render_frame_setup(&eye_pos, &eye_orient);
4222 game_render_frame( &eye_pos, &eye_orient );
4224 // save the eye position and orientation
4225 if ( Game_mode & GM_MULTIPLAYER ) {
4226 Net_player->s_info.eye_pos = eye_pos;
4227 Net_player->s_info.eye_orient = eye_orient;
4230 hud_show_target_model();
4232 // check to see if we should display the death died popup
4233 if(Game_mode & GM_DEAD_BLEW_UP){
4234 if(Game_mode & GM_MULTIPLAYER){
4235 // catch the situation where we're supposed to be warping out on this transition
4236 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4237 gameseq_post_event(GS_EVENT_DEBRIEF);
4238 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4239 Player_died_popup_wait = -1;
4243 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4244 Player_died_popup_wait = -1;
4250 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4251 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4252 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4253 if(!popupdead_is_active()){
4257 Player_multi_died_check = -1;
4261 render3_time2 = timer_get_fixed_seconds();
4262 render2_time1 = timer_get_fixed_seconds();
4265 game_get_framerate();
4266 game_show_framerate();
4268 game_show_time_left();
4270 // Draw the 2D HUD gauges
4271 if(supernova_active() < 3){
4272 game_render_hud_2d();
4275 game_set_view_clip();
4277 // Draw 3D HUD gauges
4278 game_render_hud_3d(&eye_pos, &eye_orient);
4282 render2_time2 = timer_get_fixed_seconds();
4284 // maybe render and process the dead popup
4285 game_maybe_do_dead_popup(flFrametime);
4287 // start timing frame
4288 timing_frame_stop();
4289 // timing_display(30, 10);
4291 // If a regular popup is active, don't flip (popup code flips)
4292 if( !popup_running_state() ){
4293 flip_time1 = timer_get_fixed_seconds();
4294 game_flip_page_and_time_it();
4295 flip_time2 = timer_get_fixed_seconds();
4299 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4302 game_show_standalone_framerate();
4306 game_do_training_checks();
4309 // process lightning (nebula only)
4312 total_time2 = timer_get_fixed_seconds();
4314 // Got some timing numbers
4315 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4316 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4317 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4318 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4319 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4322 demo_do_frame_end();
4324 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4330 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4331 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4332 // died. This resulted in screwed up death sequences.
4334 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4335 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4336 static int timer_paused=0;
4337 #if defined(TIMER_TEST) && !defined(NDEBUG)
4338 static int stop_count,start_count;
4339 static int time_stopped,time_started;
4341 int saved_timestamp_ticker = -1;
4343 void game_reset_time()
4345 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4349 // Last_time = timer_get_fixed_seconds();
4355 void game_stop_time()
4357 if (timer_paused==0) {
4359 time = timer_get_fixed_seconds();
4360 // Save how much time progressed so far in the frame so we can
4361 // use it when we unpause.
4362 Last_delta_time = time - Last_time;
4364 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4365 if (Last_delta_time < 0) {
4366 #if defined(TIMER_TEST) && !defined(NDEBUG)
4367 Int3(); //get Matt!!!!
4369 Last_delta_time = 0;
4371 #if defined(TIMER_TEST) && !defined(NDEBUG)
4372 time_stopped = time;
4375 // Stop the timer_tick stuff...
4376 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4377 saved_timestamp_ticker = timestamp_ticker;
4381 #if defined(TIMER_TEST) && !defined(NDEBUG)
4386 void game_start_time()
4389 Assert(timer_paused >= 0);
4390 if (timer_paused==0) {
4392 time = timer_get_fixed_seconds();
4393 #if defined(TIMER_TEST) && !defined(NDEBUG)
4395 Int3(); //get Matt!!!!
4398 // Take current time, and set it backwards to account for time
4399 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4400 // will be correct when it goes to calculate the frametime next
4402 Last_time = time - Last_delta_time;
4403 #if defined(TIMER_TEST) && !defined(NDEBUG)
4404 time_started = time;
4407 // Restore the timer_tick stuff...
4408 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4409 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4410 timestamp_ticker = saved_timestamp_ticker;
4411 saved_timestamp_ticker = -1;
4414 #if defined(TIMER_TEST) && !defined(NDEBUG)
4420 void game_set_frametime(int state)
4423 float frame_cap_diff;
4425 thistime = timer_get_fixed_seconds();
4427 if ( Last_time == 0 )
4428 Frametime = F1_0 / 30;
4430 Frametime = thistime - Last_time;
4432 // Frametime = F1_0 / 30;
4434 fix debug_frametime = Frametime; // Just used to display frametime.
4436 // If player hasn't entered mission yet, make frame take 1/4 second.
4437 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4440 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4442 fix frame_speed = F1_0 / Debug_dump_frames;
4444 if (Frametime > frame_speed ){
4445 nprintf(("warning","slow frame: %x\n",Frametime));
4448 thistime = timer_get_fixed_seconds();
4449 Frametime = thistime - Last_time;
4450 } while (Frametime < frame_speed );
4452 Frametime = frame_speed;
4456 Assert( Framerate_cap > 0 );
4458 // Cap the framerate so it doesn't get too high.
4462 cap = F1_0/Framerate_cap;
4463 if (Frametime < cap) {
4464 thistime = cap - Frametime;
4465 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4466 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4468 thistime = timer_get_fixed_seconds();
4472 if((Game_mode & GM_STANDALONE_SERVER) &&
4473 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4475 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4476 Sleep((DWORD)(frame_cap_diff*1000));
4478 thistime += fl2f((frame_cap_diff));
4480 Frametime = thistime - Last_time;
4483 // If framerate is too low, cap it.
4484 if (Frametime > MAX_FRAMETIME) {
4486 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4488 // to remove warnings in release build
4489 debug_frametime = fl2f(flFrametime);
4491 Frametime = MAX_FRAMETIME;
4494 Frametime = fixmul(Frametime, Game_time_compression);
4496 Last_time = thistime;
4497 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4499 flFrametime = f2fl(Frametime);
4500 //if(!(Game_mode & GM_PLAYING_DEMO)){
4501 timestamp_inc(flFrametime);
4503 /* if ((Framecount > 0) && (Framecount < 10)) {
4504 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4509 // This is called from game_do_frame(), and from navmap_do_frame()
4510 void game_update_missiontime()
4512 // TODO JAS: Put in if and move this into game_set_frametime,
4513 // fix navmap to call game_stop/start_time
4514 //if ( !timer_paused )
4515 Missiontime += Frametime;
4518 void game_do_frame()
4520 game_set_frametime(GS_STATE_GAME_PLAY);
4521 game_update_missiontime();
4523 if (Game_mode & GM_STANDALONE_SERVER) {
4524 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4527 if ( game_single_step && (last_single_step == game_single_step) ) {
4528 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4529 while( key_checkch() == 0 )
4531 os_set_title( XSTR( "FreeSpace", 171) );
4532 Last_time = timer_get_fixed_seconds();
4535 last_single_step = game_single_step;
4537 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4538 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4542 Keep_mouse_centered = 0;
4543 monitor_update(); // Update monitor variables
4546 void multi_maybe_do_frame()
4548 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4553 int Joymouse_button_status = 0;
4555 // Flush all input devices
4563 Joymouse_button_status = 0;
4565 //mprintf(("Game flush!\n" ));
4568 // function for multiplayer only which calls game_do_state_common() when running the
4570 void game_do_dc_networking()
4572 Assert( Game_mode & GM_MULTIPLAYER );
4574 game_do_state_common( gameseq_get_state() );
4577 // Call this whenever in a loop, or when you need to check for a keystroke.
4578 int game_check_key()
4584 // convert keypad enter to normal enter
4585 if ((k & KEY_MASK) == KEY_PADENTER)
4586 k = (k & ~KEY_MASK) | KEY_ENTER;
4593 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4594 static int Demo_show_trailer_timestamp = 0;
4596 void demo_reset_trailer_timer()
4598 Demo_show_trailer_timestamp = timer_get_milliseconds();
4601 void demo_maybe_show_trailer(int k)
4604 // if key pressed, reset demo trailer timer
4606 demo_reset_trailer_timer();
4610 // if mouse moved, reset demo trailer timer
4613 mouse_get_delta(&dx, &dy);
4614 if ( (dx > 0) || (dy > 0) ) {
4615 demo_reset_trailer_timer();
4619 // if joystick has moved, reset demo trailer timer
4622 joy_get_delta(&dx, &dy);
4623 if ( (dx > 0) || (dy > 0) ) {
4624 demo_reset_trailer_timer();
4628 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4629 // the low-level code. Ugly, I know... but was the simplest and most
4632 // if 30 seconds since last demo trailer time reset, launch movie
4633 if ( os_foreground() ) {
4634 int now = timer_get_milliseconds();
4635 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4636 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4638 movie_play( NOX("fstrailer2.mve") );
4639 demo_reset_trailer_timer();
4647 // same as game_check_key(), except this is used while actually in the game. Since there
4648 // generally are differences between game control keys and general UI keys, makes sense to
4649 // have seperate functions for each case. If you are not checking a game control while in a
4650 // mission, you should probably be using game_check_key() instead.
4655 if (!os_foreground()) {
4660 // If we're in a single player game, pause it.
4661 if (!(Game_mode & GM_MULTIPLAYER)){
4662 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4663 game_process_pause_key();
4671 demo_maybe_show_trailer(k);
4674 // Move the mouse cursor with the joystick.
4675 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4676 // Move the mouse cursor with the joystick
4680 joy_get_pos( &jx, &jy, &jz, &jr );
4682 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4683 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4686 mouse_get_real_pos( &mx, &my );
4687 mouse_set_pos( mx+dx, my+dy );
4692 m = mouse_down(MOUSE_LEFT_BUTTON);
4694 if ( j != Joymouse_button_status ) {
4695 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4696 Joymouse_button_status = j;
4698 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4699 } else if ( (!j) && (m) ) {
4700 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4705 // if we should be ignoring keys because of some multiplayer situations
4706 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4710 // If a popup is running, don't process all the Fn keys
4711 if( popup_active() ) {
4715 state = gameseq_get_state();
4717 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4720 case KEY_DEBUGGED + KEY_BACKSP:
4725 launch_context_help();
4730 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4732 // don't allow f2 while warping out in multiplayer
4733 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4738 case GS_STATE_INITIAL_PLAYER_SELECT:
4739 case GS_STATE_OPTIONS_MENU:
4740 case GS_STATE_HUD_CONFIG:
4741 case GS_STATE_CONTROL_CONFIG:
4742 case GS_STATE_DEATH_DIED:
4743 case GS_STATE_DEATH_BLEW_UP:
4744 case GS_STATE_VIEW_MEDALS:
4748 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4755 // hotkey selection screen -- only valid from briefing and beyond.
4758 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) ) {
4759 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4765 case KEY_DEBUGGED + KEY_F3:
4766 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4769 case KEY_DEBUGGED + KEY_F4:
4770 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4774 if(Game_mode & GM_MULTIPLAYER){
4775 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4776 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4780 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4781 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4787 case KEY_ESC | KEY_SHIFTED:
4788 // make sure to quit properly out of multiplayer
4789 if(Game_mode & GM_MULTIPLAYER){
4790 multi_quit_game(PROMPT_NONE);
4793 gameseq_post_event( GS_EVENT_QUIT_GAME );
4798 case KEY_DEBUGGED + KEY_P:
4801 case KEY_PRINT_SCRN:
4803 static int counter = 0;
4808 sprintf( tmp_name, NOX("screen%02d"), counter );
4810 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4811 gr_print_screen(tmp_name);
4819 case KEY_SHIFTED | KEY_ENTER: {
4821 #if !defined(NDEBUG)
4823 if ( Game_mode & GM_NORMAL ){
4827 // if we're in multiplayer mode, do some special networking
4828 if(Game_mode & GM_MULTIPLAYER){
4829 debug_console(game_do_dc_networking);
4836 if ( Game_mode & GM_NORMAL )
4850 gameseq_post_event(GS_EVENT_QUIT_GAME);
4853 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4856 void camera_set_position( vector *pos )
4861 void camera_set_orient( matrix *orient )
4863 Camera_orient = *orient;
4866 void camera_set_velocity( vector *vel, int instantaneous )
4868 Camera_desired_velocity.x = 0.0f;
4869 Camera_desired_velocity.y = 0.0f;
4870 Camera_desired_velocity.z = 0.0f;
4872 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4873 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4874 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4876 if ( instantaneous ) {
4877 Camera_velocity = Camera_desired_velocity;
4885 vector new_vel, delta_pos;
4887 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4888 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4889 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4891 Camera_velocity = new_vel;
4893 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4895 vm_vec_add2( &Camera_pos, &delta_pos );
4897 float ot = Camera_time+0.0f;
4899 Camera_time += flFrametime;
4901 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4904 tmp.z = 4.739f; // always go this fast forward.
4906 // pick x and y velocities so they are always on a
4907 // circle with a 25 m radius.
4909 float tmp_angle = frand()*PI2;
4911 tmp.x = 22.0f * (float)sin(tmp_angle);
4912 tmp.y = -22.0f * (float)cos(tmp_angle);
4914 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4916 //mprintf(( "Changing velocity!\n" ));
4917 camera_set_velocity( &tmp, 0 );
4920 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4921 vector tmp = { 0.0f, 0.0f, 0.0f };
4922 camera_set_velocity( &tmp, 0 );
4927 void end_demo_campaign_do()
4929 #if defined(FS2_DEMO)
4930 // show upsell screens
4931 demo_upsell_show_screens();
4932 #elif defined(OEM_BUILD)
4933 // show oem upsell screens
4934 oem_upsell_show_screens();
4937 // drop into main hall
4938 gameseq_post_event( GS_EVENT_MAIN_MENU );
4941 // All code to process events. This is the only place
4942 // that you should change the state of the game.
4943 void game_process_event( int current_state, int event )
4945 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4948 case GS_EVENT_SIMULATOR_ROOM:
4949 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4952 case GS_EVENT_MAIN_MENU:
4953 gameseq_set_state(GS_STATE_MAIN_MENU);
4956 case GS_EVENT_OPTIONS_MENU:
4957 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4960 case GS_EVENT_BARRACKS_MENU:
4961 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4964 case GS_EVENT_TECH_MENU:
4965 gameseq_set_state(GS_STATE_TECH_MENU);
4968 case GS_EVENT_TRAINING_MENU:
4969 gameseq_set_state(GS_STATE_TRAINING_MENU);
4972 case GS_EVENT_START_GAME:
4973 Select_default_ship = 0;
4974 Player_multi_died_check = -1;
4975 gameseq_set_state(GS_STATE_CMD_BRIEF);
4978 case GS_EVENT_START_BRIEFING:
4979 gameseq_set_state(GS_STATE_BRIEFING);
4982 case GS_EVENT_DEBRIEF:
4983 // did we end the campaign in the main freespace 2 single player campaign?
4984 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4985 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4987 gameseq_set_state(GS_STATE_DEBRIEF);
4990 Player_multi_died_check = -1;
4993 case GS_EVENT_SHIP_SELECTION:
4994 gameseq_set_state( GS_STATE_SHIP_SELECT );
4997 case GS_EVENT_WEAPON_SELECTION:
4998 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5001 case GS_EVENT_ENTER_GAME:
5003 // maybe start recording a demo
5005 demo_start_record("test.fsd");
5009 if (Game_mode & GM_MULTIPLAYER) {
5010 // if we're respawning, make sure we change the view mode so that the hud shows up
5011 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5015 gameseq_set_state(GS_STATE_GAME_PLAY);
5017 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5020 Player_multi_died_check = -1;
5022 // clear multiplayer button info
5023 extern button_info Multi_ship_status_bi;
5024 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5026 Start_time = f2fl(timer_get_approx_seconds());
5028 mprintf(("Entering game at time = %7.3f\n", Start_time));
5032 case GS_EVENT_START_GAME_QUICK:
5033 Select_default_ship = 1;
5034 gameseq_post_event(GS_EVENT_ENTER_GAME);
5038 case GS_EVENT_END_GAME:
5039 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5040 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5041 gameseq_set_state(GS_STATE_MAIN_MENU);
5046 Player_multi_died_check = -1;
5049 case GS_EVENT_QUIT_GAME:
5050 main_hall_stop_music();
5051 main_hall_stop_ambient();
5052 gameseq_set_state(GS_STATE_QUIT_GAME);
5054 Player_multi_died_check = -1;
5057 case GS_EVENT_GAMEPLAY_HELP:
5058 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5061 case GS_EVENT_PAUSE_GAME:
5062 gameseq_push_state(GS_STATE_GAME_PAUSED);
5065 case GS_EVENT_DEBUG_PAUSE_GAME:
5066 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5069 case GS_EVENT_TRAINING_PAUSE:
5070 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5073 case GS_EVENT_PREVIOUS_STATE:
5074 gameseq_pop_state();
5077 case GS_EVENT_TOGGLE_FULLSCREEN:
5078 #ifndef HARDWARE_ONLY
5080 if ( gr_screen.mode == GR_SOFTWARE ) {
5081 gr_init( GR_640, GR_DIRECTDRAW );
5082 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5083 gr_init( GR_640, GR_SOFTWARE );
5089 case GS_EVENT_TOGGLE_GLIDE:
5091 if ( gr_screen.mode != GR_GLIDE ) {
5092 gr_init( GR_640, GR_GLIDE );
5094 gr_init( GR_640, GR_SOFTWARE );
5099 case GS_EVENT_LOAD_MISSION_MENU:
5100 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5103 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5104 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5107 case GS_EVENT_HUD_CONFIG:
5108 gameseq_push_state( GS_STATE_HUD_CONFIG );
5111 case GS_EVENT_CONTROL_CONFIG:
5112 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5115 case GS_EVENT_DEATH_DIED:
5116 gameseq_set_state( GS_STATE_DEATH_DIED );
5119 case GS_EVENT_DEATH_BLEW_UP:
5120 if ( current_state == GS_STATE_DEATH_DIED ) {
5121 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5122 event_music_player_death();
5124 // multiplayer clients set their extra check here
5125 if(Game_mode & GM_MULTIPLAYER){
5126 // set the multi died absolute last chance check
5127 Player_multi_died_check = time(NULL);
5130 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5134 case GS_EVENT_NEW_CAMPAIGN:
5135 if (!mission_load_up_campaign()){
5136 readyroom_continue_campaign();
5139 Player_multi_died_check = -1;
5142 case GS_EVENT_CAMPAIGN_CHEAT:
5143 if (!mission_load_up_campaign()){
5145 // bash campaign value
5146 extern char Main_hall_campaign_cheat[512];
5149 // look for the mission
5150 for(idx=0; idx<Campaign.num_missions; idx++){
5151 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5152 Campaign.next_mission = idx;
5153 Campaign.prev_mission = idx - 1;
5160 readyroom_continue_campaign();
5163 Player_multi_died_check = -1;
5166 case GS_EVENT_CAMPAIGN_ROOM:
5167 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5170 case GS_EVENT_CMD_BRIEF:
5171 gameseq_set_state(GS_STATE_CMD_BRIEF);
5174 case GS_EVENT_RED_ALERT:
5175 gameseq_set_state(GS_STATE_RED_ALERT);
5178 case GS_EVENT_CREDITS:
5179 gameseq_set_state( GS_STATE_CREDITS );
5182 case GS_EVENT_VIEW_MEDALS:
5183 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5186 case GS_EVENT_SHOW_GOALS:
5187 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5190 case GS_EVENT_HOTKEY_SCREEN:
5191 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5194 // multiplayer stuff follow these comments
5196 case GS_EVENT_MULTI_JOIN_GAME:
5197 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5200 case GS_EVENT_MULTI_HOST_SETUP:
5201 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5204 case GS_EVENT_MULTI_CLIENT_SETUP:
5205 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5208 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5209 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5212 case GS_EVENT_MULTI_STD_WAIT:
5213 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5216 case GS_EVENT_STANDALONE_MAIN:
5217 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5220 case GS_EVENT_MULTI_PAUSE:
5221 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5224 case GS_EVENT_INGAME_PRE_JOIN:
5225 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5228 case GS_EVENT_EVENT_DEBUG:
5229 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5232 // Start a warpout where player automatically goes 70 no matter what
5233 // and can't cancel out of it.
5234 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5235 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5237 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5238 Player->saved_viewer_mode = Viewer_mode;
5239 Player->control_mode = PCM_WARPOUT_STAGE1;
5240 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5241 Warpout_time = 0.0f; // Start timer!
5244 case GS_EVENT_PLAYER_WARPOUT_START:
5245 if ( Player->control_mode != PCM_NORMAL ) {
5246 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5248 Player->saved_viewer_mode = Viewer_mode;
5249 Player->control_mode = PCM_WARPOUT_STAGE1;
5250 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5251 Warpout_time = 0.0f; // Start timer!
5252 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5256 case GS_EVENT_PLAYER_WARPOUT_STOP:
5257 if ( Player->control_mode != PCM_NORMAL ) {
5258 if ( !Warpout_forced ) { // cannot cancel forced warpout
5259 Player->control_mode = PCM_NORMAL;
5260 Viewer_mode = Player->saved_viewer_mode;
5261 hud_subspace_notify_abort();
5262 mprintf(( "Player put back to normal mode.\n" ));
5263 if ( Warpout_sound > -1 ) {
5264 snd_stop( Warpout_sound );
5271 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5272 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5273 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5274 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5276 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5277 shipfx_warpout_start( Player_obj );
5278 Player->control_mode = PCM_WARPOUT_STAGE2;
5279 Player->saved_viewer_mode = Viewer_mode;
5280 Viewer_mode |= VM_WARP_CHASE;
5282 vector tmp = Player_obj->pos;
5284 ship_get_eye( &tmp, &tmp_m, Player_obj );
5285 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5286 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5287 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5289 camera_set_position( &tmp );
5290 camera_set_orient( &Player_obj->orient );
5291 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5293 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5294 camera_set_velocity( &tmp_vel, 1);
5298 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5299 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5300 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5301 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5303 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5304 Player->control_mode = PCM_WARPOUT_STAGE3;
5308 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5309 mprintf(( "Player warped out. Going to debriefing!\n" ));
5310 Player->control_mode = PCM_NORMAL;
5311 Viewer_mode = Player->saved_viewer_mode;
5314 // we have a special debriefing screen for multiplayer furballs
5315 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5316 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5318 // do the normal debriefing for all other situations
5320 gameseq_post_event(GS_EVENT_DEBRIEF);
5324 case GS_EVENT_STANDALONE_POSTGAME:
5325 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5328 case GS_EVENT_INITIAL_PLAYER_SELECT:
5329 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5332 case GS_EVENT_GAME_INIT:
5333 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5334 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5336 // see if the command line option has been set to use the last pilot, and act acoordingly
5337 if( player_select_get_last_pilot() ) {
5338 // always enter the main menu -- do the automatic network startup stuff elsewhere
5339 // so that we still have valid checks for networking modes, etc.
5340 gameseq_set_state(GS_STATE_MAIN_MENU);
5342 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5347 case GS_EVENT_MULTI_MISSION_SYNC:
5348 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5351 case GS_EVENT_MULTI_START_GAME:
5352 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5355 case GS_EVENT_MULTI_HOST_OPTIONS:
5356 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5359 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5360 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5363 case GS_EVENT_TEAM_SELECT:
5364 gameseq_set_state(GS_STATE_TEAM_SELECT);
5367 case GS_EVENT_END_CAMPAIGN:
5368 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5371 case GS_EVENT_END_DEMO:
5372 gameseq_set_state(GS_STATE_END_DEMO);
5375 case GS_EVENT_LOOP_BRIEF:
5376 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5385 // Called when a state is being left.
5386 // The current state is still at old_state, but as soon as
5387 // this function leaves, then the current state will become
5388 // new state. You should never try to change the state
5389 // in here... if you think you need to, you probably really
5390 // need to post an event, not change the state.
5391 void game_leave_state( int old_state, int new_state )
5393 int end_mission = 1;
5395 switch (new_state) {
5396 case GS_STATE_GAME_PAUSED:
5397 case GS_STATE_DEBUG_PAUSED:
5398 case GS_STATE_OPTIONS_MENU:
5399 case GS_STATE_CONTROL_CONFIG:
5400 case GS_STATE_MISSION_LOG_SCROLLBACK:
5401 case GS_STATE_DEATH_DIED:
5402 case GS_STATE_SHOW_GOALS:
5403 case GS_STATE_HOTKEY_SCREEN:
5404 case GS_STATE_MULTI_PAUSED:
5405 case GS_STATE_TRAINING_PAUSED:
5406 case GS_STATE_EVENT_DEBUG:
5407 case GS_STATE_GAMEPLAY_HELP:
5408 end_mission = 0; // these events shouldn't end a mission
5412 switch (old_state) {
5413 case GS_STATE_BRIEFING:
5414 brief_stop_voices();
5415 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5416 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5417 && (new_state != GS_STATE_TEAM_SELECT) ){
5418 common_select_close();
5419 if ( new_state == GS_STATE_MAIN_MENU ) {
5420 freespace_stop_mission();
5424 // COMMAND LINE OPTION
5425 if (Cmdline_multi_stream_chat_to_file){
5426 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5427 cfclose(Multi_chat_stream);
5431 case GS_STATE_DEBRIEF:
5432 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5437 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5438 multi_df_debrief_close();
5441 case GS_STATE_LOAD_MISSION_MENU:
5442 mission_load_menu_close();
5445 case GS_STATE_SIMULATOR_ROOM:
5449 case GS_STATE_CAMPAIGN_ROOM:
5450 campaign_room_close();
5453 case GS_STATE_CMD_BRIEF:
5454 if (new_state == GS_STATE_OPTIONS_MENU) {
5459 if (new_state == GS_STATE_MAIN_MENU)
5460 freespace_stop_mission();
5465 case GS_STATE_RED_ALERT:
5469 case GS_STATE_SHIP_SELECT:
5470 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5471 new_state != GS_STATE_HOTKEY_SCREEN &&
5472 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5473 common_select_close();
5474 if ( new_state == GS_STATE_MAIN_MENU ) {
5475 freespace_stop_mission();
5480 case GS_STATE_WEAPON_SELECT:
5481 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5482 new_state != GS_STATE_HOTKEY_SCREEN &&
5483 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5484 common_select_close();
5485 if ( new_state == GS_STATE_MAIN_MENU ) {
5486 freespace_stop_mission();
5491 case GS_STATE_TEAM_SELECT:
5492 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5493 new_state != GS_STATE_HOTKEY_SCREEN &&
5494 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5495 common_select_close();
5496 if ( new_state == GS_STATE_MAIN_MENU ) {
5497 freespace_stop_mission();
5502 case GS_STATE_MAIN_MENU:
5503 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5510 case GS_STATE_OPTIONS_MENU:
5511 //game_start_time();
5512 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5513 multi_join_clear_game_list();
5515 options_menu_close();
5518 case GS_STATE_BARRACKS_MENU:
5519 if(new_state != GS_STATE_VIEW_MEDALS){
5524 case GS_STATE_MISSION_LOG_SCROLLBACK:
5525 hud_scrollback_close();
5528 case GS_STATE_TRAINING_MENU:
5529 training_menu_close();
5532 case GS_STATE_GAME_PLAY:
5533 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5534 player_save_target_and_weapon_link_prefs();
5535 game_stop_looped_sounds();
5538 sound_env_disable();
5539 joy_ff_stop_effects();
5541 // stop game time under certain conditions
5542 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5547 // shut down any recording or playing demos
5552 // when in multiplayer and going back to the main menu, send a leave game packet
5553 // right away (before calling stop mission). stop_mission was taking to long to
5554 // close mission down and I want people to get notified ASAP.
5555 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5556 multi_quit_game(PROMPT_NONE);
5559 freespace_stop_mission();
5560 Game_time_compression = F1_0;
5564 case GS_STATE_TECH_MENU:
5568 case GS_STATE_TRAINING_PAUSED:
5569 Training_num_lines = 0;
5570 // fall through to GS_STATE_GAME_PAUSED
5572 case GS_STATE_GAME_PAUSED:
5574 if ( end_mission ) {
5579 case GS_STATE_DEBUG_PAUSED:
5582 pause_debug_close();
5586 case GS_STATE_HUD_CONFIG:
5590 // join/start a game
5591 case GS_STATE_MULTI_JOIN_GAME:
5592 if(new_state != GS_STATE_OPTIONS_MENU){
5593 multi_join_game_close();
5597 case GS_STATE_MULTI_HOST_SETUP:
5598 case GS_STATE_MULTI_CLIENT_SETUP:
5599 // if this is just the host going into the options screen, don't do anything
5600 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5604 // close down the proper state
5605 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5606 multi_create_game_close();
5608 multi_game_client_setup_close();
5611 // COMMAND LINE OPTION
5612 if (Cmdline_multi_stream_chat_to_file){
5613 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5614 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5615 cfclose(Multi_chat_stream);
5620 case GS_STATE_CONTROL_CONFIG:
5621 control_config_close();
5624 case GS_STATE_DEATH_DIED:
5625 Game_mode &= ~GM_DEAD_DIED;
5627 // early end while respawning or blowing up in a multiplayer game
5628 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5630 freespace_stop_mission();
5634 case GS_STATE_DEATH_BLEW_UP:
5635 Game_mode &= ~GM_DEAD_BLEW_UP;
5637 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5638 // to determine if I should do anything.
5639 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5641 freespace_stop_mission();
5644 // if we are not respawing as an observer or as a player, our new state will not
5645 // be gameplay state.
5646 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5647 game_stop_time(); // hasn't been called yet!!
5648 freespace_stop_mission();
5654 case GS_STATE_CREDITS:
5658 case GS_STATE_VIEW_MEDALS:
5662 case GS_STATE_SHOW_GOALS:
5663 mission_show_goals_close();
5666 case GS_STATE_HOTKEY_SCREEN:
5667 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5668 mission_hotkey_close();
5672 case GS_STATE_MULTI_MISSION_SYNC:
5673 // if we're moving into the options menu, don't do anything
5674 if(new_state == GS_STATE_OPTIONS_MENU){
5678 Assert( Game_mode & GM_MULTIPLAYER );
5680 if ( new_state == GS_STATE_GAME_PLAY ){
5681 // palette_restore_palette();
5683 // change a couple of flags to indicate our state!!!
5684 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5685 send_netplayer_update_packet();
5687 // set the game mode
5688 Game_mode |= GM_IN_MISSION;
5692 case GS_STATE_VIEW_CUTSCENES:
5693 cutscenes_screen_close();
5696 case GS_STATE_MULTI_STD_WAIT:
5697 multi_standalone_wait_close();
5700 case GS_STATE_STANDALONE_MAIN:
5701 standalone_main_close();
5702 if(new_state == GS_STATE_MULTI_STD_WAIT){
5703 init_multiplayer_stats();
5707 case GS_STATE_MULTI_PAUSED:
5708 // if ( end_mission ){
5713 case GS_STATE_INGAME_PRE_JOIN:
5714 multi_ingame_select_close();
5717 case GS_STATE_STANDALONE_POSTGAME:
5718 multi_standalone_postgame_close();
5721 case GS_STATE_INITIAL_PLAYER_SELECT:
5722 player_select_close();
5725 case GS_STATE_MULTI_START_GAME:
5726 multi_start_game_close();
5729 case GS_STATE_MULTI_HOST_OPTIONS:
5730 multi_host_options_close();
5733 case GS_STATE_END_OF_CAMPAIGN:
5734 mission_campaign_end_close();
5737 case GS_STATE_LOOP_BRIEF:
5743 // Called when a state is being entered.
5744 // The current state is set to the state we're entering at
5745 // this point, and old_state is set to the state we're coming
5746 // from. You should never try to change the state
5747 // in here... if you think you need to, you probably really
5748 // need to post an event, not change the state.
5750 void game_enter_state( int old_state, int new_state )
5752 switch (new_state) {
5753 case GS_STATE_MAIN_MENU:
5754 // in multiplayer mode, be sure that we are not doing networking anymore.
5755 if ( Game_mode & GM_MULTIPLAYER ) {
5756 Assert( Net_player != NULL );
5757 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5760 Game_time_compression = F1_0;
5762 // determine which ship this guy is currently based on
5763 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5766 if (Player->on_bastion) {
5774 case GS_STATE_BRIEFING:
5775 main_hall_stop_music();
5776 main_hall_stop_ambient();
5778 if (Game_mode & GM_NORMAL) {
5779 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5780 // MWA: or from options or hotkey screens
5781 // JH: or if the command brief state already did this
5782 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5783 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5784 && (old_state != GS_STATE_CMD_BRIEF) ) {
5785 if ( !game_start_mission() ) // this should put us into a new state on failure!
5789 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5790 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5791 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5793 Game_time_compression = F1_0;
5795 if ( red_alert_mission() ) {
5796 gameseq_post_event(GS_EVENT_RED_ALERT);
5803 case GS_STATE_DEBRIEF:
5804 game_stop_looped_sounds();
5805 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5806 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5811 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5812 multi_df_debrief_init();
5815 case GS_STATE_LOAD_MISSION_MENU:
5816 mission_load_menu_init();
5819 case GS_STATE_SIMULATOR_ROOM:
5823 case GS_STATE_CAMPAIGN_ROOM:
5824 campaign_room_init();
5827 case GS_STATE_RED_ALERT:
5828 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5832 case GS_STATE_CMD_BRIEF: {
5833 int team_num = 0; // team number used as index for which cmd brief to use.
5835 if (old_state == GS_STATE_OPTIONS_MENU) {
5839 main_hall_stop_music();
5840 main_hall_stop_ambient();
5842 if (Game_mode & GM_NORMAL) {
5843 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5844 // MWA: or from options or hotkey screens
5845 // JH: or if the command brief state already did this
5846 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5847 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5848 if ( !game_start_mission() ) // this should put us into a new state on failure!
5853 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5854 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5855 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5857 cmd_brief_init(team_num);
5863 case GS_STATE_SHIP_SELECT:
5867 case GS_STATE_WEAPON_SELECT:
5868 weapon_select_init();
5871 case GS_STATE_TEAM_SELECT:
5875 case GS_STATE_GAME_PAUSED:
5880 case GS_STATE_DEBUG_PAUSED:
5881 // game_stop_time();
5882 // os_set_title("FreeSpace - PAUSED");
5885 case GS_STATE_TRAINING_PAUSED:
5892 case GS_STATE_OPTIONS_MENU:
5894 options_menu_init();
5897 case GS_STATE_GAME_PLAY:
5898 // coming from the gameplay state or the main menu, we might need to load the mission
5899 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5900 if ( !game_start_mission() ) // this should put us into a new state.
5905 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5906 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5907 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5908 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5909 (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) ) {
5910 // JAS: Used to do all paging here.
5914 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5918 main_hall_stop_music();
5919 main_hall_stop_ambient();
5920 event_music_first_pattern(); // start the first pattern
5923 // special code that restores player ship selection and weapons loadout when doing a quick start
5924 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5925 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5926 wss_direct_restore_loadout();
5930 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5931 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5932 event_music_first_pattern(); // start the first pattern
5935 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5936 event_music_first_pattern(); // start the first pattern
5938 player_restore_target_and_weapon_link_prefs();
5940 Game_mode |= GM_IN_MISSION;
5943 // required to truely make mouse deltas zeroed in debug mouse code
5944 void mouse_force_pos(int x, int y);
5945 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5950 // only start time if in single player, or coming from multi wait state
5953 (Game_mode & GM_NORMAL) &&
5954 (old_state != GS_STATE_VIEW_CUTSCENES)
5956 (Game_mode & GM_MULTIPLAYER) && (
5957 (old_state == GS_STATE_MULTI_PAUSED) ||
5958 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5964 // when coming from the multi paused state, reset the timestamps
5965 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5966 multi_reset_timestamps();
5969 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5970 // initialize all object update details
5971 multi_oo_gameplay_init();
5974 // under certain circumstances, the server should reset the object update rate limiting stuff
5975 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5976 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5978 // reinitialize the rate limiting system for all clients
5979 multi_oo_rate_init_all();
5982 // multiplayer clients should always re-initialize their control info rate limiting system
5983 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5984 multi_oo_rate_init_all();
5988 if(Game_mode & GM_MULTIPLAYER){
5989 multi_ping_reset_players();
5992 Game_subspace_effect = 0;
5993 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5994 Game_subspace_effect = 1;
5995 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5996 game_start_subspace_ambient_sound();
6000 sound_env_set(&Game_sound_env);
6001 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6003 // clear multiplayer button info i
6004 extern button_info Multi_ship_status_bi;
6005 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6008 case GS_STATE_HUD_CONFIG:
6012 case GS_STATE_MULTI_JOIN_GAME:
6013 multi_join_clear_game_list();
6015 if (old_state != GS_STATE_OPTIONS_MENU) {
6016 multi_join_game_init();
6021 case GS_STATE_MULTI_HOST_SETUP:
6022 // don't reinitialize if we're coming back from the host options screen
6023 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6024 multi_create_game_init();
6029 case GS_STATE_MULTI_CLIENT_SETUP:
6030 if (old_state != GS_STATE_OPTIONS_MENU) {
6031 multi_game_client_setup_init();
6036 case GS_STATE_CONTROL_CONFIG:
6037 control_config_init();
6040 case GS_STATE_TECH_MENU:
6044 case GS_STATE_BARRACKS_MENU:
6045 if(old_state != GS_STATE_VIEW_MEDALS){
6050 case GS_STATE_MISSION_LOG_SCROLLBACK:
6051 hud_scrollback_init();
6054 case GS_STATE_DEATH_DIED:
6055 Player_died_time = timestamp(10);
6057 if(!(Game_mode & GM_MULTIPLAYER)){
6058 player_show_death_message();
6060 Game_mode |= GM_DEAD_DIED;
6063 case GS_STATE_DEATH_BLEW_UP:
6064 if ( !popupdead_is_active() ) {
6065 Player_ai->target_objnum = -1;
6068 // stop any local EMP effect
6071 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6072 Game_mode |= GM_DEAD_BLEW_UP;
6073 Show_viewing_from_self = 0;
6075 // timestamp how long we should wait before displaying the died popup
6076 if ( !popupdead_is_active() ) {
6077 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6081 case GS_STATE_GAMEPLAY_HELP:
6082 gameplay_help_init();
6085 case GS_STATE_CREDITS:
6086 main_hall_stop_music();
6087 main_hall_stop_ambient();
6091 case GS_STATE_VIEW_MEDALS:
6092 medal_main_init(Player);
6095 case GS_STATE_SHOW_GOALS:
6096 mission_show_goals_init();
6099 case GS_STATE_HOTKEY_SCREEN:
6100 mission_hotkey_init();
6103 case GS_STATE_MULTI_MISSION_SYNC:
6104 // if we're coming from the options screen, don't do any
6105 if(old_state == GS_STATE_OPTIONS_MENU){
6109 switch(Multi_sync_mode){
6110 case MULTI_SYNC_PRE_BRIEFING:
6111 // if moving from game forming to the team select state
6114 case MULTI_SYNC_POST_BRIEFING:
6115 // if moving from briefing into the mission itself
6118 // tell everyone that we're now loading data
6119 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6120 send_netplayer_update_packet();
6122 // JAS: Used to do all paging here!!!!
6124 Net_player->state = NETPLAYER_STATE_WAITING;
6125 send_netplayer_update_packet();
6127 Game_time_compression = F1_0;
6129 case MULTI_SYNC_INGAME:
6135 case GS_STATE_VIEW_CUTSCENES:
6136 cutscenes_screen_init();
6139 case GS_STATE_MULTI_STD_WAIT:
6140 multi_standalone_wait_init();
6143 case GS_STATE_STANDALONE_MAIN:
6144 // don't initialize if we're coming from one of these 2 states unless there are no
6145 // players left (reset situation)
6146 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6147 standalone_main_init();
6151 case GS_STATE_MULTI_PAUSED:
6155 case GS_STATE_INGAME_PRE_JOIN:
6156 multi_ingame_select_init();
6159 case GS_STATE_STANDALONE_POSTGAME:
6160 multi_standalone_postgame_init();
6163 case GS_STATE_INITIAL_PLAYER_SELECT:
6164 player_select_init();
6167 case GS_STATE_MULTI_START_GAME:
6168 multi_start_game_init();
6171 case GS_STATE_MULTI_HOST_OPTIONS:
6172 multi_host_options_init();
6175 case GS_STATE_END_OF_CAMPAIGN:
6176 mission_campaign_end_init();
6179 case GS_STATE_LOOP_BRIEF:
6186 // do stuff that may need to be done regardless of state
6187 void game_do_state_common(int state,int no_networking)
6189 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6190 snd_do_frame(); // update sound system
6191 event_music_do_frame(); // music needs to play across many states
6193 multi_log_process();
6195 if (no_networking) {
6199 // maybe do a multiplayer frame based on game mode and state type
6200 if (Game_mode & GM_MULTIPLAYER) {
6202 case GS_STATE_OPTIONS_MENU:
6203 case GS_STATE_GAMEPLAY_HELP:
6204 case GS_STATE_HOTKEY_SCREEN:
6205 case GS_STATE_HUD_CONFIG:
6206 case GS_STATE_CONTROL_CONFIG:
6207 case GS_STATE_MISSION_LOG_SCROLLBACK:
6208 case GS_STATE_SHOW_GOALS:
6209 case GS_STATE_VIEW_CUTSCENES:
6210 case GS_STATE_EVENT_DEBUG:
6211 multi_maybe_do_frame();
6215 game_do_networking();
6219 // Called once a frame.
6220 // You should never try to change the state
6221 // in here... if you think you need to, you probably really
6222 // need to post an event, not change the state.
6223 int Game_do_state_should_skip = 0;
6224 void game_do_state(int state)
6226 // always lets the do_state_common() function determine if the state should be skipped
6227 Game_do_state_should_skip = 0;
6229 // legal to set the should skip state anywhere in this function
6230 game_do_state_common(state); // do stuff that may need to be done regardless of state
6232 if(Game_do_state_should_skip){
6237 case GS_STATE_MAIN_MENU:
6238 game_set_frametime(GS_STATE_MAIN_MENU);
6239 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6242 main_hall_do(flFrametime);
6246 case GS_STATE_OPTIONS_MENU:
6247 game_set_frametime(GS_STATE_OPTIONS_MENU);
6248 options_menu_do_frame(flFrametime);
6251 case GS_STATE_BARRACKS_MENU:
6252 game_set_frametime(GS_STATE_BARRACKS_MENU);
6253 barracks_do_frame(flFrametime);
6256 case GS_STATE_TRAINING_MENU:
6257 game_set_frametime(GS_STATE_TRAINING_MENU);
6258 training_menu_do_frame(flFrametime);
6261 case GS_STATE_TECH_MENU:
6262 game_set_frametime(GS_STATE_TECH_MENU);
6263 techroom_do_frame(flFrametime);
6266 case GS_STATE_GAMEPLAY_HELP:
6267 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6268 gameplay_help_do_frame(flFrametime);
6271 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6275 case GS_STATE_GAME_PAUSED:
6279 case GS_STATE_DEBUG_PAUSED:
6281 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6286 case GS_STATE_TRAINING_PAUSED:
6287 game_training_pause_do();
6290 case GS_STATE_LOAD_MISSION_MENU:
6291 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6292 mission_load_menu_do();
6295 case GS_STATE_BRIEFING:
6296 game_set_frametime(GS_STATE_BRIEFING);
6297 brief_do_frame(flFrametime);
6300 case GS_STATE_DEBRIEF:
6301 game_set_frametime(GS_STATE_DEBRIEF);
6302 debrief_do_frame(flFrametime);
6305 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6306 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6307 multi_df_debrief_do();
6310 case GS_STATE_SHIP_SELECT:
6311 game_set_frametime(GS_STATE_SHIP_SELECT);
6312 ship_select_do(flFrametime);
6315 case GS_STATE_WEAPON_SELECT:
6316 game_set_frametime(GS_STATE_WEAPON_SELECT);
6317 weapon_select_do(flFrametime);
6320 case GS_STATE_MISSION_LOG_SCROLLBACK:
6321 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6322 hud_scrollback_do_frame(flFrametime);
6325 case GS_STATE_HUD_CONFIG:
6326 game_set_frametime(GS_STATE_HUD_CONFIG);
6327 hud_config_do_frame(flFrametime);
6330 case GS_STATE_MULTI_JOIN_GAME:
6331 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6332 multi_join_game_do_frame();
6335 case GS_STATE_MULTI_HOST_SETUP:
6336 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6337 multi_create_game_do();
6340 case GS_STATE_MULTI_CLIENT_SETUP:
6341 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6342 multi_game_client_setup_do_frame();
6345 case GS_STATE_CONTROL_CONFIG:
6346 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6347 control_config_do_frame(flFrametime);
6350 case GS_STATE_DEATH_DIED:
6354 case GS_STATE_DEATH_BLEW_UP:
6358 case GS_STATE_SIMULATOR_ROOM:
6359 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6360 sim_room_do_frame(flFrametime);
6363 case GS_STATE_CAMPAIGN_ROOM:
6364 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6365 campaign_room_do_frame(flFrametime);
6368 case GS_STATE_RED_ALERT:
6369 game_set_frametime(GS_STATE_RED_ALERT);
6370 red_alert_do_frame(flFrametime);
6373 case GS_STATE_CMD_BRIEF:
6374 game_set_frametime(GS_STATE_CMD_BRIEF);
6375 cmd_brief_do_frame(flFrametime);
6378 case GS_STATE_CREDITS:
6379 game_set_frametime(GS_STATE_CREDITS);
6380 credits_do_frame(flFrametime);
6383 case GS_STATE_VIEW_MEDALS:
6384 game_set_frametime(GS_STATE_VIEW_MEDALS);
6388 case GS_STATE_SHOW_GOALS:
6389 game_set_frametime(GS_STATE_SHOW_GOALS);
6390 mission_show_goals_do_frame(flFrametime);
6393 case GS_STATE_HOTKEY_SCREEN:
6394 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6395 mission_hotkey_do_frame(flFrametime);
6398 case GS_STATE_VIEW_CUTSCENES:
6399 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6400 cutscenes_screen_do_frame();
6403 case GS_STATE_MULTI_STD_WAIT:
6404 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6405 multi_standalone_wait_do();
6408 case GS_STATE_STANDALONE_MAIN:
6409 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6410 standalone_main_do();
6413 case GS_STATE_MULTI_PAUSED:
6414 game_set_frametime(GS_STATE_MULTI_PAUSED);
6418 case GS_STATE_TEAM_SELECT:
6419 game_set_frametime(GS_STATE_TEAM_SELECT);
6423 case GS_STATE_INGAME_PRE_JOIN:
6424 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6425 multi_ingame_select_do();
6428 case GS_STATE_EVENT_DEBUG:
6430 game_set_frametime(GS_STATE_EVENT_DEBUG);
6431 game_show_event_debug(flFrametime);
6435 case GS_STATE_STANDALONE_POSTGAME:
6436 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6437 multi_standalone_postgame_do();
6440 case GS_STATE_INITIAL_PLAYER_SELECT:
6441 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6445 case GS_STATE_MULTI_MISSION_SYNC:
6446 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6450 case GS_STATE_MULTI_START_GAME:
6451 game_set_frametime(GS_STATE_MULTI_START_GAME);
6452 multi_start_game_do();
6455 case GS_STATE_MULTI_HOST_OPTIONS:
6456 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6457 multi_host_options_do();
6460 case GS_STATE_END_OF_CAMPAIGN:
6461 mission_campaign_end_do();
6464 case GS_STATE_END_DEMO:
6465 game_set_frametime(GS_STATE_END_DEMO);
6466 end_demo_campaign_do();
6469 case GS_STATE_LOOP_BRIEF:
6470 game_set_frametime(GS_STATE_LOOP_BRIEF);
6474 } // end switch(gs_current_state)
6478 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6479 int game_do_ram_check(int ram_in_bytes)
6481 if ( ram_in_bytes < 30*1024*1024 ) {
6482 int allowed_to_run = 1;
6483 if ( ram_in_bytes < 25*1024*1024 ) {
6488 int Freespace_total_ram_MB;
6489 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6491 if ( allowed_to_run ) {
6493 sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run. If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE). Any memory allocated to SmartDrive is not usable by applications\n\nPress 'OK' to continue running with less than the minimum required memory\n", 193), Freespace_total_ram_MB, Freespace_total_ram_MB);
6498 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6499 if ( msgbox_rval == IDCANCEL ) {
6506 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);
6508 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6519 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6520 // If so, copy it over and remove the update directory.
6521 void game_maybe_update_launcher(char *exe_dir)
6524 char src_filename[MAX_PATH];
6525 char dest_filename[MAX_PATH];
6527 strcpy(src_filename, exe_dir);
6528 strcat(src_filename, NOX("\\update\\freespace.exe"));
6530 strcpy(dest_filename, exe_dir);
6531 strcat(dest_filename, NOX("\\freespace.exe"));
6533 // see if src_filename exists
6535 fp = fopen(src_filename, "rb");
6541 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6543 // copy updated freespace.exe to freespace exe dir
6544 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6545 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 );
6549 // delete the file in the update directory
6550 DeleteFile(src_filename);
6552 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6553 char update_dir[MAX_PATH];
6554 strcpy(update_dir, exe_dir);
6555 strcat(update_dir, NOX("\\update"));
6556 RemoveDirectory(update_dir);
6562 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6566 int sub_total_destroyed = 0;
6570 // get the total for all his children
6571 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6572 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6575 // find the # of faces for this _individual_ object
6576 total = submodel_get_num_polys(model_num, sm);
6577 if(strstr(pm->submodel[sm].name, "-destroyed")){
6578 sub_total_destroyed = total;
6582 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6585 *out_total += total + sub_total;
6586 *out_destroyed_total += sub_total_destroyed;
6589 #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);
6590 void game_spew_pof_info()
6592 char *pof_list[1000];
6595 int idx, model_num, i, j;
6597 int total, root_total, model_total, destroyed_total, counted;
6601 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6603 // spew info on all the pofs
6609 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6614 for(idx=0; idx<num_files; idx++, counted++){
6615 sprintf(str, "%s.pof", pof_list[idx]);
6616 model_num = model_load(str, 0, NULL);
6618 pm = model_get(model_num);
6620 // if we have a real model
6625 // go through and print all raw submodels
6626 cfputs("RAW\n", out);
6629 for (i=0; i<pm->n_models; i++) {
6630 total = submodel_get_num_polys(model_num, i);
6632 model_total += total;
6633 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6636 sprintf(str, "Model total %d\n", model_total);
6639 // now go through and do it by LOD
6640 cfputs("BY LOD\n\n", out);
6641 for(i=0; i<pm->n_detail_levels; i++){
6642 sprintf(str, "LOD %d\n", i);
6646 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6648 destroyed_total = 0;
6649 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6650 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6653 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6656 sprintf(str, "TOTAL: %d\n", total + root_total);
6658 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6660 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6663 cfputs("------------------------------------------------------------------------\n\n", out);
6667 if(counted >= MAX_POLYGON_MODELS - 5){
6680 game_spew_pof_info();
6683 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6688 // Don't let more than one instance of Freespace run.
6689 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6691 SetForegroundWindow(hwnd);
6696 // Find out how much RAM is on this machine
6699 ms.dwLength = sizeof(MEMORYSTATUS);
6700 GlobalMemoryStatus(&ms);
6701 Freespace_total_ram = ms.dwTotalPhys;
6703 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6707 if ( ms.dwTotalVirtual < 1024 ) {
6708 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6712 if (!vm_init(24*1024*1024)) {
6713 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 );
6717 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6719 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);
6729 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6730 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6731 seem worth bothering with.
6735 lResult = RegOpenKeyEx(
6736 HKEY_LOCAL_MACHINE, // Where it is
6737 "Software\\Microsoft\\DirectX", // name of key
6738 NULL, // DWORD reserved
6739 KEY_QUERY_VALUE, // Allows all changes
6740 &hKey // Location to store key
6743 if (lResult == ERROR_SUCCESS) {
6745 DWORD dwType, dwLen;
6748 lResult = RegQueryValueEx(
6749 hKey, // Handle to key
6750 "Version", // The values name
6751 NULL, // DWORD reserved
6752 &dwType, // What kind it is
6753 (ubyte *) version, // value to set
6754 &dwLen // How many bytes to set
6757 if (lResult == ERROR_SUCCESS) {
6758 dx_version = atoi(strstr(version, ".") + 1);
6762 DWORD dwType, dwLen;
6765 lResult = RegQueryValueEx(
6766 hKey, // Handle to key
6767 "InstalledVersion", // The values name
6768 NULL, // DWORD reserved
6769 &dwType, // What kind it is
6770 (ubyte *) &val, // value to set
6771 &dwLen // How many bytes to set
6774 if (lResult == ERROR_SUCCESS) {
6782 if (dx_version < 3) {
6783 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6784 "latest version of DirectX at:\n\n"
6785 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6787 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6788 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6793 //=====================================================
6794 // Make sure we're running in the right directory.
6798 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6799 char *p = exe_dir + strlen(exe_dir);
6801 // chop off the filename
6802 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6808 if ( strlen(exe_dir) > 0 ) {
6809 SetCurrentDirectory(exe_dir);
6812 // check for updated freespace.exe
6813 game_maybe_update_launcher(exe_dir);
6821 extern void windebug_memwatch_init();
6822 windebug_memwatch_init();
6826 parse_cmdline(szCmdLine);
6828 #ifdef STANDALONE_ONLY_BUILD
6830 nprintf(("Network", "Standalone running"));
6833 nprintf(("Network", "Standalone running"));
6841 // maybe spew pof stuff
6842 if(Cmdline_spew_pof_info){
6843 game_spew_pof_info();
6848 // non-demo, non-standalone, play the intro movie
6853 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) ){
6855 #if defined(OEM_BUILD)
6856 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6858 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6859 #endif // defined(OEM_BUILD)
6864 if ( !Is_standalone ) {
6866 // release -- movies always play
6869 // 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
6871 // movie_play( NOX("intro.mve"), 0 );
6873 // debug version, movie will only play with -showmovies
6874 #elif !defined(NDEBUG)
6877 // movie_play( NOX("intro.mve"), 0);
6880 if ( Cmdline_show_movies )
6881 movie_play( NOX("intro.mve"), 0 );
6890 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6892 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6896 // only important for non THREADED mode
6899 state = gameseq_process_events();
6900 if ( state == GS_STATE_QUIT_GAME ){
6907 demo_upsell_show_screens();
6909 #elif defined(OEM_BUILD)
6910 // show upsell screens on exit
6911 oem_upsell_show_screens();
6918 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6924 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6926 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6928 // Do nothing here - RecordExceptionInfo() has already done
6929 // everything that is needed. Actually this code won't even
6930 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6931 // the __except clause.
6937 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6938 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6944 // launcher the fslauncher program on exit
6945 void game_launch_launcher_on_exit()
6949 PROCESS_INFORMATION pi;
6950 char cmd_line[2048];
6951 char original_path[1024] = "";
6953 memset( &si, 0, sizeof(STARTUPINFO) );
6957 _getcwd(original_path, 1023);
6959 // set up command line
6960 strcpy(cmd_line, original_path);
6961 strcat(cmd_line, "\\");
6962 strcat(cmd_line, LAUNCHER_FNAME);
6963 strcat(cmd_line, " -straight_to_update");
6965 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6966 cmd_line, // pointer to command line string
6967 NULL, // pointer to process security attributes
6968 NULL, // pointer to thread security attributes
6969 FALSE, // handle inheritance flag
6970 CREATE_DEFAULT_ERROR_MODE, // creation flags
6971 NULL, // pointer to new environment block
6972 NULL, // pointer to current directory name
6973 &si, // pointer to STARTUPINFO
6974 &pi // pointer to PROCESS_INFORMATION
6976 // to eliminate build warnings
6986 // This function is called when FreeSpace terminates normally.
6988 void game_shutdown(void)
6994 // don't ever flip a page on the standalone!
6995 if(!(Game_mode & GM_STANDALONE_SERVER)){
7001 // if the player has left the "player select" screen and quit the game without actually choosing
7002 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7003 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7007 // load up common multiplayer icons
7008 multi_unload_common_icons();
7010 shockwave_close(); // release any memory used by shockwave system
7011 fireball_close(); // free fireball system
7012 ship_close(); // free any memory that was allocated for the ships
7013 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7014 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7015 bm_unload_all(); // free bitmaps
7016 mission_campaign_close(); // close out the campaign stuff
7017 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7019 #ifdef MULTI_USE_LAG
7023 // the menu close functions will unload the bitmaps if they were displayed during the game
7024 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7027 training_menu_close();
7030 extern void joy_close();
7033 audiostream_close();
7035 event_music_close();
7039 // HACKITY HACK HACK
7040 // if this flag is set, we should be firing up the launcher when exiting freespace
7041 extern int Multi_update_fireup_launcher_on_exit;
7042 if(Multi_update_fireup_launcher_on_exit){
7043 game_launch_launcher_on_exit();
7047 // game_stop_looped_sounds()
7049 // This function will call the appropriate stop looped sound functions for those
7050 // modules which use looping sounds. It is not enough just to stop a looping sound
7051 // at the DirectSound level, the game is keeping track of looping sounds, and this
7052 // function is used to inform the game that looping sounds are being halted.
7054 void game_stop_looped_sounds()
7056 hud_stop_looped_locking_sounds();
7057 hud_stop_looped_engine_sounds();
7058 afterburner_stop_sounds();
7059 player_stop_looped_sounds();
7060 obj_snd_stop_all(); // stop all object-linked persistant sounds
7061 game_stop_subspace_ambient_sound();
7062 snd_stop(Radar_static_looping);
7063 Radar_static_looping = -1;
7064 snd_stop(Target_static_looping);
7065 shipfx_stop_engine_wash_sound();
7066 Target_static_looping = -1;
7069 //////////////////////////////////////////////////////////////////////////
7071 // Code for supporting an animating mouse pointer
7074 //////////////////////////////////////////////////////////////////////////
7076 typedef struct animating_obj
7085 static animating_obj Animating_mouse;
7087 // ----------------------------------------------------------------------------
7088 // init_animating_pointer()
7090 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7091 // gets properly initialized
7093 void init_animating_pointer()
7095 Animating_mouse.first_frame = -1;
7096 Animating_mouse.num_frames = 0;
7097 Animating_mouse.current_frame = -1;
7098 Animating_mouse.time = 0.0f;
7099 Animating_mouse.elapsed_time = 0.0f;
7102 // ----------------------------------------------------------------------------
7103 // load_animating_pointer()
7105 // Called at game init to load in the frames for the animating mouse pointer
7107 // input: filename => filename of animation file that holds the animation
7109 void load_animating_pointer(char *filename, int dx, int dy)
7114 init_animating_pointer();
7116 am = &Animating_mouse;
7117 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7118 if ( am->first_frame == -1 )
7119 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7120 am->current_frame = 0;
7121 am->time = am->num_frames / i2fl(fps);
7124 // ----------------------------------------------------------------------------
7125 // unload_animating_pointer()
7127 // Called at game shutdown to free the memory used to store the animation frames
7129 void unload_animating_pointer()
7134 am = &Animating_mouse;
7135 for ( i = 0; i < am->num_frames; i++ ) {
7136 Assert( (am->first_frame+i) >= 0 );
7137 bm_release(am->first_frame + i);
7140 am->first_frame = -1;
7142 am->current_frame = -1;
7145 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7146 void game_render_mouse(float frametime)
7151 // if animating cursor exists, play the next frame
7152 am = &Animating_mouse;
7153 if ( am->first_frame != -1 ) {
7154 mouse_get_pos(&mx, &my);
7155 am->elapsed_time += frametime;
7156 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7157 if ( am->current_frame >= am->num_frames ) {
7158 am->current_frame = 0;
7159 am->elapsed_time = 0.0f;
7161 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7165 // ----------------------------------------------------------------------------
7166 // game_maybe_draw_mouse()
7168 // determines whether to draw the mouse pointer at all, and what frame of
7169 // animation to use if the mouse is animating
7171 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7173 // input: frametime => elapsed frame time in seconds since last call
7175 void game_maybe_draw_mouse(float frametime)
7179 game_state = gameseq_get_state();
7181 switch ( game_state ) {
7182 case GS_STATE_GAME_PAUSED:
7183 // case GS_STATE_MULTI_PAUSED:
7184 case GS_STATE_GAME_PLAY:
7185 case GS_STATE_DEATH_DIED:
7186 case GS_STATE_DEATH_BLEW_UP:
7187 if ( popup_active() || popupdead_is_active() ) {
7199 if ( !Mouse_hidden )
7200 game_render_mouse(frametime);
7204 void game_do_training_checks()
7208 waypoint_list *wplp;
7210 if (Training_context & TRAINING_CONTEXT_SPEED) {
7211 s = (int) Player_obj->phys_info.fspeed;
7212 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7213 if (!Training_context_speed_set) {
7214 Training_context_speed_set = 1;
7215 Training_context_speed_timestamp = timestamp();
7219 Training_context_speed_set = 0;
7222 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7223 wplp = &Waypoint_lists[Training_context_path];
7224 if (wplp->count > Training_context_goal_waypoint) {
7225 i = Training_context_goal_waypoint;
7227 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7228 if (d <= Training_context_distance) {
7229 Training_context_at_waypoint = i;
7230 if (Training_context_goal_waypoint == i) {
7231 Training_context_goal_waypoint++;
7232 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7239 if (i == wplp->count)
7242 } while (i != Training_context_goal_waypoint);
7246 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7247 Players_target = Player_ai->target_objnum;
7248 Players_targeted_subsys = Player_ai->targeted_subsys;
7249 Players_target_timestamp = timestamp();
7253 /////////// Following is for event debug view screen
7257 #define EVENT_DEBUG_MAX 5000
7258 #define EVENT_DEBUG_EVENT 0x8000
7260 int Event_debug_index[EVENT_DEBUG_MAX];
7263 void game_add_event_debug_index(int n, int indent)
7265 if (ED_count < EVENT_DEBUG_MAX)
7266 Event_debug_index[ED_count++] = n | (indent << 16);
7269 void game_add_event_debug_sexp(int n, int indent)
7274 if (Sexp_nodes[n].first >= 0) {
7275 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7276 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7280 game_add_event_debug_index(n, indent);
7281 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7282 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7284 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7287 void game_event_debug_init()
7292 for (e=0; e<Num_mission_events; e++) {
7293 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7294 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7298 void game_show_event_debug(float frametime)
7302 int font_height, font_width;
7304 static int scroll_offset = 0;
7306 k = game_check_key();
7312 if (scroll_offset < 0)
7322 scroll_offset -= 20;
7323 if (scroll_offset < 0)
7328 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7332 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7338 gr_set_color_fast(&Color_bright);
7340 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7342 gr_set_color_fast(&Color_normal);
7344 gr_get_string_size(&font_width, &font_height, NOX("test"));
7345 y_max = gr_screen.max_h - font_height - 5;
7349 while (k < ED_count) {
7350 if (y_index > y_max)
7353 z = Event_debug_index[k];
7354 if (z & EVENT_DEBUG_EVENT) {
7356 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7357 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7358 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7359 Mission_events[z].repeat_count, Mission_events[z].interval);
7367 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7368 switch (Sexp_nodes[z & 0x7fff].value) {
7370 strcat(buf, NOX(" (True)"));
7374 strcat(buf, NOX(" (False)"));
7377 case SEXP_KNOWN_TRUE:
7378 strcat(buf, NOX(" (Always true)"));
7381 case SEXP_KNOWN_FALSE:
7382 strcat(buf, NOX(" (Always false)"));
7385 case SEXP_CANT_EVAL:
7386 strcat(buf, NOX(" (Can't eval)"));
7390 case SEXP_NAN_FOREVER:
7391 strcat(buf, NOX(" (Not a number)"));
7396 gr_printf(10, y_index, buf);
7397 y_index += font_height;
7410 extern int Tmap_npixels;
7412 int Tmap_num_too_big = 0;
7413 int Num_models_needing_splitting = 0;
7415 void Time_model( int modelnum )
7417 // mprintf(( "Timing ship '%s'\n", si->name ));
7419 vector eye_pos, model_pos;
7420 matrix eye_orient, model_orient;
7422 polymodel *pm = model_get( modelnum );
7424 int l = strlen(pm->filename);
7426 if ( (l == '/') || (l=='\\') || (l==':')) {
7432 char *pof_file = &pm->filename[l];
7434 int model_needs_splitting = 0;
7436 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7438 for (i=0; i<pm->n_textures; i++ ) {
7439 char filename[1024];
7442 int bmp_num = pm->original_textures[i];
7443 if ( bmp_num > -1 ) {
7444 bm_get_palette(pm->original_textures[i], pal, filename );
7446 bm_get_info( pm->original_textures[i],&w, &h );
7449 if ( (w > 512) || (h > 512) ) {
7450 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7452 model_needs_splitting++;
7455 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7459 if ( model_needs_splitting ) {
7460 Num_models_needing_splitting++;
7462 eye_orient = model_orient = vmd_identity_matrix;
7463 eye_pos = model_pos = vmd_zero_vector;
7465 eye_pos.z = -pm->rad*2.0f;
7467 vector eye_to_model;
7469 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7470 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7472 fix t1 = timer_get_fixed_seconds();
7475 ta.p = ta.b = ta.h = 0.0f;
7480 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7482 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7484 modelstats_num_polys = modelstats_num_verts = 0;
7486 while( ta.h < PI2 ) {
7489 vm_angles_2_matrix(&m1, &ta );
7490 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7497 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7499 model_clear_instance( modelnum );
7500 model_set_detail_level(0); // use highest detail level
7501 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7509 int k = key_inkey();
7510 if ( k == KEY_ESC ) {
7515 fix t2 = timer_get_fixed_seconds();
7517 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7518 //bitmaps_used_this_frame /= framecount;
7520 modelstats_num_polys /= framecount;
7521 modelstats_num_verts /= framecount;
7523 Tmap_npixels /=framecount;
7526 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7527 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 );
7528 // 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 );
7534 int Time_models = 0;
7535 DCF_BOOL( time_models, Time_models );
7537 void Do_model_timings_test()
7541 if ( !Time_models ) return;
7543 mprintf(( "Timing models!\n" ));
7547 ubyte model_used[MAX_POLYGON_MODELS];
7548 int model_id[MAX_POLYGON_MODELS];
7549 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7554 for (i=0; i<Num_ship_types; i++ ) {
7555 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7557 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7558 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7561 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7562 if ( !Texture_fp ) return;
7564 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7565 if ( !Time_fp ) return;
7567 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7568 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7570 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7571 if ( model_used[i] ) {
7572 Time_model( model_id[i] );
7576 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7577 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7586 // Call this function when you want to inform the player that a feature is not
7587 // enabled in the DEMO version of FreSpace
7588 void game_feature_not_in_demo_popup()
7590 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7593 // format the specified time (fixed point) into a nice string
7594 void game_format_time(fix m_time,char *time_str)
7597 int hours,minutes,seconds;
7600 mtime = f2fl(m_time);
7602 // get the hours, minutes and seconds
7603 hours = (int)(mtime / 3600.0f);
7605 mtime -= (3600.0f * (float)hours);
7607 seconds = (int)mtime%60;
7608 minutes = (int)mtime/60;
7610 // print the hour if necessary
7612 sprintf(time_str,XSTR( "%d:", 201),hours);
7613 // if there are less than 10 minutes, print a leading 0
7615 strcpy(tmp,NOX("0"));
7616 strcat(time_str,tmp);
7620 // print the minutes
7622 sprintf(tmp,XSTR( "%d:", 201),minutes);
7623 strcat(time_str,tmp);
7625 sprintf(time_str,XSTR( "%d:", 201),minutes);
7628 // print the seconds
7630 strcpy(tmp,NOX("0"));
7631 strcat(time_str,tmp);
7633 sprintf(tmp,"%d",seconds);
7634 strcat(time_str,tmp);
7637 // Stuff version string in *str.
7638 void get_version_string(char *str)
7641 if ( FS_VERSION_BUILD == 0 ) {
7642 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7644 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7647 #if defined (FS2_DEMO)
7649 #elif defined (OEM_BUILD)
7650 strcat(str, " (OEM)");
7656 char myname[_MAX_PATH];
7657 int namelen, major, minor, build, waste;
7658 unsigned int buf_size;
7664 // Find my EXE file name
7665 hMod = GetModuleHandle(NULL);
7666 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7668 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7669 infop = (char *)malloc(version_size);
7670 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7672 // get the product version
7673 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7674 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7676 sprintf(str,"Dv%d.%02d",major, minor);
7678 sprintf(str,"v%d.%02d",major, minor);
7683 void get_version_string_short(char *str)
7685 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7688 // ----------------------------------------------------------------
7690 // OEM UPSELL SCREENS BEGIN
7692 // ----------------------------------------------------------------
7693 #if defined(OEM_BUILD)
7695 #define NUM_OEM_UPSELL_SCREENS 3
7696 #define OEM_UPSELL_SCREEN_DELAY 10000
7698 static int Oem_upsell_bitmaps_loaded = 0;
7699 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7700 static int Oem_upsell_screen_number = 0;
7701 static int Oem_upsell_show_next_bitmap_time;
7704 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7717 static int Oem_normal_cursor = -1;
7718 static int Oem_web_cursor = -1;
7719 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7720 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7722 void oem_upsell_next_screen()
7724 Oem_upsell_screen_number++;
7725 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7726 // extra long delay, mouse shown on last upsell
7727 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7731 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7735 void oem_upsell_load_bitmaps()
7739 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7740 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7744 void oem_upsell_unload_bitmaps()
7748 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7749 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7750 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7755 Oem_upsell_bitmaps_loaded = 0;
7758 // clickable hotspot on 3rd OEM upsell screen
7759 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7761 28, 350, 287, 96 // x, y, w, h
7764 45, 561, 460, 152 // x, y, w, h
7768 void oem_upsell_show_screens()
7770 int current_time, k;
7773 if ( !Oem_upsell_bitmaps_loaded ) {
7774 oem_upsell_load_bitmaps();
7775 Oem_upsell_bitmaps_loaded = 1;
7778 // may use upsell screens more than once
7779 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7780 Oem_upsell_screen_number = 0;
7786 int nframes; // used to pass, not really needed (should be 1)
7787 Oem_normal_cursor = gr_get_cursor_bitmap();
7788 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7789 Assert(Oem_web_cursor >= 0);
7790 if (Oem_web_cursor < 0) {
7791 Oem_web_cursor = Oem_normal_cursor;
7796 //oem_reset_trailer_timer();
7798 current_time = timer_get_milliseconds();
7803 // advance screen on keypress or timeout
7804 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7805 oem_upsell_next_screen();
7808 // check if we are done
7809 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7810 Oem_upsell_screen_number--;
7813 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7818 // show me the upsell
7819 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7820 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7824 // if this is the 3rd upsell, make it clickable, d00d
7825 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7827 int button_state = mouse_get_pos(&mx, &my);
7828 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])
7829 && (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]) )
7832 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7835 if (button_state & MOUSE_LEFT_BUTTON) {
7837 multi_pxo_url(OEM_UPSELL_URL);
7841 // switch cursor back to normal one
7842 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7847 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7857 oem_upsell_unload_bitmaps();
7859 // switch cursor back to normal one
7860 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7864 #endif // defined(OEM_BUILD)
7865 // ----------------------------------------------------------------
7867 // OEM UPSELL SCREENS END
7869 // ----------------------------------------------------------------
7873 // ----------------------------------------------------------------
7875 // DEMO UPSELL SCREENS BEGIN
7877 // ----------------------------------------------------------------
7881 //#define NUM_DEMO_UPSELL_SCREENS 4
7883 #define NUM_DEMO_UPSELL_SCREENS 2
7884 #define DEMO_UPSELL_SCREEN_DELAY 3000
7886 static int Demo_upsell_bitmaps_loaded = 0;
7887 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7888 static int Demo_upsell_screen_number = 0;
7889 static int Demo_upsell_show_next_bitmap_time;
7892 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7905 void demo_upsell_next_screen()
7907 Demo_upsell_screen_number++;
7908 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7909 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7911 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7915 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7916 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7917 #ifndef HARDWARE_ONLY
7918 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7925 void demo_upsell_load_bitmaps()
7929 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7930 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7934 void demo_upsell_unload_bitmaps()
7938 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7939 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7940 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7945 Demo_upsell_bitmaps_loaded = 0;
7948 void demo_upsell_show_screens()
7950 int current_time, k;
7953 if ( !Demo_upsell_bitmaps_loaded ) {
7954 demo_upsell_load_bitmaps();
7955 Demo_upsell_bitmaps_loaded = 1;
7958 // may use upsell screens more than once
7959 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7960 Demo_upsell_screen_number = 0;
7967 demo_reset_trailer_timer();
7969 current_time = timer_get_milliseconds();
7976 // don't time out, wait for keypress
7978 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7979 demo_upsell_next_screen();
7984 demo_upsell_next_screen();
7987 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7988 Demo_upsell_screen_number--;
7991 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7996 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7997 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8002 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8012 demo_upsell_unload_bitmaps();
8017 // ----------------------------------------------------------------
8019 // DEMO UPSELL SCREENS END
8021 // ----------------------------------------------------------------
8024 // ----------------------------------------------------------------
8026 // Subspace Ambient Sound START
8028 // ----------------------------------------------------------------
8030 static int Subspace_ambient_left_channel = -1;
8031 static int Subspace_ambient_right_channel = -1;
8034 void game_start_subspace_ambient_sound()
8036 if ( Subspace_ambient_left_channel < 0 ) {
8037 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8040 if ( Subspace_ambient_right_channel < 0 ) {
8041 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8045 void game_stop_subspace_ambient_sound()
8047 if ( Subspace_ambient_left_channel >= 0 ) {
8048 snd_stop(Subspace_ambient_left_channel);
8049 Subspace_ambient_left_channel = -1;
8052 if ( Subspace_ambient_right_channel >= 0 ) {
8053 snd_stop(Subspace_ambient_right_channel);
8054 Subspace_ambient_right_channel = -1;
8058 // ----------------------------------------------------------------
8060 // Subspace Ambient Sound END
8062 // ----------------------------------------------------------------
8064 // ----------------------------------------------------------------
8066 // CDROM detection code START
8068 // ----------------------------------------------------------------
8070 #define CD_SIZE_72_MINUTE_MAX (697000000)
8072 uint game_get_cd_used_space(char *path)
8076 char use_path[512] = "";
8077 char sub_path[512] = "";
8078 WIN32_FIND_DATA find;
8081 // recurse through all files and directories
8082 strcpy(use_path, path);
8083 strcat(use_path, "*.*");
8084 find_handle = FindFirstFile(use_path, &find);
8087 if(find_handle == INVALID_HANDLE_VALUE){
8093 // subdirectory. make sure to ignore . and ..
8094 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8096 strcpy(sub_path, path);
8097 strcat(sub_path, find.cFileName);
8098 strcat(sub_path, "\\");
8099 total += game_get_cd_used_space(sub_path);
8101 total += (uint)find.nFileSizeLow;
8103 } while(FindNextFile(find_handle, &find));
8106 FindClose(find_handle);
8118 // if volume_name is non-null, the CD name must match that
8119 int find_freespace_cd(char *volume_name)
8122 char oldpath[MAX_PATH];
8126 int volume_match = 0;
8130 GetCurrentDirectory(MAX_PATH, oldpath);
8132 for (i = 0; i < 26; i++)
8138 path[0] = (char)('A'+i);
8139 if (GetDriveType(path) == DRIVE_CDROM) {
8141 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8142 nprintf(("CD", "CD volume: %s\n", volume));
8144 // check for any CD volume
8145 int volume1_present = 0;
8146 int volume2_present = 0;
8147 int volume3_present = 0;
8149 char full_check[512] = "";
8151 // look for setup.exe
8152 strcpy(full_check, path);
8153 strcat(full_check, "setup.exe");
8154 find_handle = _findfirst(full_check, &find);
8155 if(find_handle != -1){
8156 volume1_present = 1;
8157 _findclose(find_handle);
8160 // look for intro.mve
8161 strcpy(full_check, path);
8162 strcat(full_check, "intro.mve");
8163 find_handle = _findfirst(full_check, &find);
8164 if(find_handle != -1){
8165 volume2_present = 1;
8166 _findclose(find_handle);
8169 // look for endpart1.mve
8170 strcpy(full_check, path);
8171 strcat(full_check, "endpart1.mve");
8172 find_handle = _findfirst(full_check, &find);
8173 if(find_handle != -1){
8174 volume3_present = 1;
8175 _findclose(find_handle);
8178 // see if we have the specific CD we're looking for
8179 if ( volume_name ) {
8181 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8185 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8189 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8193 if ( volume1_present || volume2_present || volume3_present ) {
8198 // 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
8199 if ( volume_match ){
8201 // 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
8202 if(volume2_present || volume3_present) {
8203 // first step - check to make sure its a cdrom
8204 if(GetDriveType(path) != DRIVE_CDROM){
8208 #if !defined(OEM_BUILD)
8209 // oem not on 80 min cds, so dont check tha size
8211 uint used_space = game_get_cd_used_space(path);
8212 if(used_space < CD_SIZE_72_MINUTE_MAX){
8215 #endif // !defined(OEM_BUILD)
8223 #endif // RELEASE_REAL
8229 SetCurrentDirectory(oldpath);
8238 int set_cdrom_path(int drive_num)
8242 if (drive_num < 0) { //no CD
8244 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8247 strcpy(Game_CDROM_dir,""); //set directory
8251 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8267 i = find_freespace_cd();
8269 rval = set_cdrom_path(i);
8273 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8275 nprintf(("CD", "FreeSpace CD not found\n"));
8283 int Last_cd_label_found = 0;
8284 char Last_cd_label[256];
8286 int game_cd_changed()
8293 if ( strlen(Game_CDROM_dir) == 0 ) {
8297 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8299 if ( found != Last_cd_label_found ) {
8300 Last_cd_label_found = found;
8302 mprintf(( "CD '%s' was inserted\n", label ));
8305 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8309 if ( Last_cd_label_found ) {
8310 if ( !stricmp( Last_cd_label, label )) {
8311 //mprintf(( "CD didn't change\n" ));
8313 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8317 // none found before, none found now.
8318 //mprintf(( "still no CD...\n" ));
8322 Last_cd_label_found = found;
8324 strcpy( Last_cd_label, label );
8326 strcpy( Last_cd_label, "" );
8337 // check if _any_ FreeSpace2 CDs are in the drive
8338 // return: 1 => CD now in drive
8339 // 0 => Could not find CD, they refuse to put it in the drive
8340 int game_do_cd_check(char *volume_name)
8342 #if !defined(GAME_CD_CHECK)
8348 int num_attempts = 0;
8349 int refresh_files = 0;
8351 int path_set_ok, popup_rval;
8353 cd_drive_num = find_freespace_cd(volume_name);
8354 path_set_ok = set_cdrom_path(cd_drive_num);
8355 if ( path_set_ok ) {
8357 if ( refresh_files ) {
8369 // no CD found, so prompt user
8370 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8372 if ( popup_rval != 1 ) {
8377 if ( num_attempts++ > 5 ) {
8388 // check if _any_ FreeSpace2 CDs are in the drive
8389 // return: 1 => CD now in drive
8390 // 0 => Could not find CD, they refuse to put it in the drive
8391 int game_do_cd_check_specific(char *volume_name, int cdnum)
8396 int num_attempts = 0;
8397 int refresh_files = 0;
8399 int path_set_ok, popup_rval;
8401 cd_drive_num = find_freespace_cd(volume_name);
8402 path_set_ok = set_cdrom_path(cd_drive_num);
8403 if ( path_set_ok ) {
8405 if ( refresh_files ) {
8416 // no CD found, so prompt user
8417 #if defined(DVD_MESSAGE_HACK)
8418 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8420 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8423 if ( popup_rval != 1 ) {
8428 if ( num_attempts++ > 5 ) {
8438 // only need to do this in RELEASE_REAL
8439 int game_do_cd_mission_check(char *filename)
8445 fs_builtin_mission *m = game_find_builtin_mission(filename);
8447 // check for changed CD
8448 if(game_cd_changed()){
8453 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8457 // not builtin, so do a general check (any FS2 CD will do)
8459 return game_do_cd_check();
8462 // does not have any CD requirement, do a general check
8463 if(strlen(m->cd_volume) <= 0){
8464 return game_do_cd_check();
8468 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8470 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8472 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8475 return game_do_cd_check();
8478 // did we find the cd?
8479 if(find_freespace_cd(m->cd_volume) >= 0){
8483 // make sure the volume exists
8484 int num_attempts = 0;
8485 int refresh_files = 0;
8487 int path_set_ok, popup_rval;
8489 cd_drive_num = find_freespace_cd(m->cd_volume);
8490 path_set_ok = set_cdrom_path(cd_drive_num);
8491 if ( path_set_ok ) {
8493 if ( refresh_files ) {
8500 // no CD found, so prompt user
8501 #if defined(DVD_MESSAGE_HACK)
8502 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8504 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8508 if ( popup_rval != 1 ) {
8513 if ( num_attempts++ > 5 ) {
8525 // ----------------------------------------------------------------
8527 // CDROM detection code END
8529 // ----------------------------------------------------------------
8531 // ----------------------------------------------------------------
8532 // SHIPS TBL VERIFICATION STUFF
8535 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8536 #define NUM_SHIPS_TBL_CHECKSUMS 1
8538 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8539 -463907578, // US - beta 1
8540 1696074201, // FS2 demo
8543 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8544 // -1022810006, // 1.0 FULL
8545 -1254285366 // 1.2 FULL (German)
8548 void verify_ships_tbl()
8552 Game_ships_tbl_valid = 1;
8558 // detect if the packfile exists
8559 CFILE *detect = cfopen("ships.tbl", "rb");
8560 Game_ships_tbl_valid = 0;
8564 Game_ships_tbl_valid = 0;
8568 // get the long checksum of the file
8570 cfseek(detect, 0, SEEK_SET);
8571 cf_chksum_long(detect, &file_checksum);
8575 // now compare the checksum/filesize against known #'s
8576 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8577 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8578 Game_ships_tbl_valid = 1;
8585 DCF(shipspew, "display the checksum for the current ships.tbl")
8588 CFILE *detect = cfopen("ships.tbl", "rb");
8589 // get the long checksum of the file
8591 cfseek(detect, 0, SEEK_SET);
8592 cf_chksum_long(detect, &file_checksum);
8595 dc_printf("%d", file_checksum);
8598 // ----------------------------------------------------------------
8599 // WEAPONS TBL VERIFICATION STUFF
8602 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8603 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8605 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8606 141718090, // US - beta 1
8607 -266420030, // demo 1
8610 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8611 // 399297860, // 1.0 FULL
8612 -553984927 // 1.2 FULL (german)
8615 void verify_weapons_tbl()
8619 Game_weapons_tbl_valid = 1;
8625 // detect if the packfile exists
8626 CFILE *detect = cfopen("weapons.tbl", "rb");
8627 Game_weapons_tbl_valid = 0;
8631 Game_weapons_tbl_valid = 0;
8635 // get the long checksum of the file
8637 cfseek(detect, 0, SEEK_SET);
8638 cf_chksum_long(detect, &file_checksum);
8642 // now compare the checksum/filesize against known #'s
8643 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8644 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8645 Game_weapons_tbl_valid = 1;
8652 DCF(wepspew, "display the checksum for the current weapons.tbl")
8655 CFILE *detect = cfopen("weapons.tbl", "rb");
8656 // get the long checksum of the file
8658 cfseek(detect, 0, SEEK_SET);
8659 cf_chksum_long(detect, &file_checksum);
8662 dc_printf("%d", file_checksum);
8665 // if the game is running using hacked data
8666 int game_hacked_data()
8669 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8677 void display_title_screen()
8679 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8680 ///int title_bitmap;
8683 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8684 if (title_bitmap == -1) {
8689 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8690 extern void d3d_start_frame();
8695 gr_set_bitmap(title_bitmap);
8701 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8702 extern void d3d_stop_frame();
8709 bm_unload(title_bitmap);
8710 #endif // FS2_DEMO || OEM_BUILD
8713 // return true if the game is running with "low memory", which is less than 48MB
8714 bool game_using_low_mem()
8716 if (Use_low_mem == 0) {