2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.9 2002/05/31 03:05:59 relnev
13 * Revision 1.8 2002/05/29 02:52:32 theoddone33
14 * Enable OpenGL renderer
16 * Revision 1.7 2002/05/28 08:52:03 relnev
17 * implemented two assembly stubs.
19 * cleaned up a few warnings.
21 * added a little demo hackery to make it progress a little farther.
23 * Revision 1.6 2002/05/28 06:28:20 theoddone33
24 * Filesystem mods, actually reads some data files now
26 * Revision 1.5 2002/05/28 04:07:28 theoddone33
27 * New graphics stubbing arrangement
29 * Revision 1.4 2002/05/27 22:46:52 theoddone33
30 * Remove more undefined symbols
32 * Revision 1.3 2002/05/26 23:31:18 relnev
33 * added a few files that needed to be compiled
35 * freespace.cpp: now compiles
37 * Revision 1.2 2002/05/07 03:16:44 theoddone33
38 * The Great Newline Fix
40 * Revision 1.1.1.1 2002/05/03 03:28:09 root
44 * 201 6/16/00 3:15p Jefff
45 * sim of the year dvd version changes, a few german soty localization
48 * 200 11/03/99 11:06a Jefff
51 * 199 10/26/99 5:07p Jamest
52 * fixed jeffs dumb debug code
54 * 198 10/25/99 5:53p Jefff
55 * call control_config_common_init() on startup
57 * 197 10/14/99 10:18a Daveb
58 * Fixed incorrect CD checking problem on standalone server.
60 * 196 10/13/99 9:22a Daveb
61 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
62 * related to movies. Fixed launcher spawning from PXO screen.
64 * 195 10/06/99 11:05a Jefff
65 * new oem upsell 3 hotspot coords
67 * 194 10/06/99 10:31a Jefff
70 * 193 10/01/99 9:10a Daveb
73 * 192 9/15/99 4:57a Dave
74 * Updated ships.tbl checksum
76 * 191 9/15/99 3:58a Dave
77 * Removed framerate warning at all times.
79 * 190 9/15/99 3:16a Dave
80 * Remove mt-011.fs2 from the builtin mission list.
82 * 189 9/15/99 1:45a Dave
83 * Don't init joystick on standalone. Fixed campaign mode on standalone.
84 * Fixed no-score-report problem in TvT
86 * 188 9/14/99 6:08a Dave
87 * Updated (final) single, multi, and campaign list.
89 * 187 9/14/99 3:26a Dave
90 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
91 * respawn-too-early problem. Made a few crash points safe.
93 * 186 9/13/99 4:52p Dave
96 * 185 9/12/99 8:09p Dave
97 * Fixed problem where skip-training button would cause mission messages
98 * not to get paged out for the current mission.
100 * 184 9/10/99 11:53a Dave
101 * Shutdown graphics before sound to eliminate apparent lockups when
102 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
104 * 183 9/09/99 11:40p Dave
105 * Handle an Assert() in beam code. Added supernova sounds. Play the right
106 * 2 end movies properly, based upon what the player did in the mission.
108 * 182 9/08/99 10:29p Dave
109 * Make beam sound pausing and unpausing much safer.
111 * 181 9/08/99 10:01p Dave
112 * Make sure game won't run in a drive's root directory. Make sure
113 * standalone routes suqad war messages properly to the host.
115 * 180 9/08/99 3:22p Dave
116 * Updated builtin mission list.
118 * 179 9/08/99 12:01p Jefff
119 * fixed Game_builtin_mission_list typo on Training-2.fs2
121 * 178 9/08/99 9:48a Andsager
122 * Add force feedback for engine wash.
124 * 177 9/07/99 4:01p Dave
125 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
126 * does everything properly (setting up address when binding). Remove
127 * black rectangle background from UI_INPUTBOX.
129 * 176 9/13/99 2:40a Dave
130 * Comment in full 80 minute CD check for RELEASE_REAL builds.
132 * 175 9/06/99 6:38p Dave
133 * Improved CD detection code.
135 * 174 9/06/99 1:30a Dave
136 * Intermediate checkin. Started on enforcing CD-in-drive to play the
139 * 173 9/06/99 1:16a Dave
140 * Make sure the user sees the intro movie.
142 * 172 9/04/99 8:00p Dave
143 * Fixed up 1024 and 32 bit movie support.
145 * 171 9/03/99 1:32a Dave
146 * CD checking by act. Added support to play 2 cutscenes in a row
147 * seamlessly. Fixed super low level cfile bug related to files in the
148 * root directory of a CD. Added cheat code to set campaign mission # in
151 * 170 9/01/99 10:49p Dave
152 * Added nice SquadWar checkbox to the client join wait screen.
154 * 169 9/01/99 10:14a Dave
157 * 168 8/29/99 4:51p Dave
158 * Fixed damaged checkin.
160 * 167 8/29/99 4:18p Andsager
161 * New "burst" limit for friendly damage. Also credit more damage done
162 * against large friendly ships.
164 * 166 8/27/99 6:38p Alanl
165 * crush the blasted repeating messages bug
167 * 164 8/26/99 9:09p Dave
168 * Force framerate check in everything but a RELEASE_REAL build.
170 * 163 8/26/99 9:45a Dave
171 * First pass at easter eggs and cheats.
173 * 162 8/24/99 8:55p Dave
174 * Make sure nondimming pixels work properly in tech menu.
176 * 161 8/24/99 1:49a Dave
177 * Fixed client-side afterburner stuttering. Added checkbox for no version
178 * checking on PXO join. Made button info passing more friendly between
181 * 160 8/22/99 5:53p Dave
182 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
183 * instead of ship designations for multiplayer players.
185 * 159 8/22/99 1:19p Dave
186 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
187 * which d3d cards are detected.
189 * 158 8/20/99 2:09p Dave
190 * PXO banner cycling.
192 * 157 8/19/99 10:59a Dave
193 * Packet loss detection.
195 * 156 8/19/99 10:12a Alanl
196 * preload mission-specific messages on machines greater than 48MB
198 * 155 8/16/99 4:04p Dave
199 * Big honking checkin.
201 * 154 8/11/99 5:54p Dave
202 * Fixed collision problem. Fixed standalone ghost problem.
204 * 153 8/10/99 7:59p Jefff
207 * 152 8/10/99 6:54p Dave
208 * Mad optimizations. Added paging to the nebula effect.
210 * 151 8/10/99 3:44p Jefff
211 * loads Intelligence information on startup
213 * 150 8/09/99 3:47p Dave
214 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
215 * non-nebula missions.
217 * 149 8/09/99 2:21p Andsager
218 * Fix patching from multiplayer direct to launcher update tab.
220 * 148 8/09/99 10:36a Dave
221 * Version info for game.
223 * 147 8/06/99 9:46p Dave
224 * Hopefully final changes for the demo.
226 * 146 8/06/99 3:34p Andsager
227 * Make title version info "(D)" -> "D" show up nicely
229 * 145 8/06/99 2:59p Adamp
230 * Fixed NT launcher/update problem.
232 * 144 8/06/99 1:52p Dave
233 * Bumped up MAX_BITMAPS for the demo.
235 * 143 8/06/99 12:17p Andsager
236 * Demo: down to just 1 demo dog
238 * 142 8/05/99 9:39p Dave
239 * Yet another new checksum.
241 * 141 8/05/99 6:19p Dave
242 * New demo checksums.
244 * 140 8/05/99 5:31p Andsager
245 * Up demo version 1.01
247 * 139 8/05/99 4:22p Andsager
248 * No time limit on upsell screens. Reverse order of display of upsell
251 * 138 8/05/99 4:17p Dave
252 * Tweaks to client interpolation.
254 * 137 8/05/99 3:52p Danw
256 * 136 8/05/99 3:01p Danw
258 * 135 8/05/99 2:43a Anoop
259 * removed duplicate definition.
261 * 134 8/05/99 2:13a Dave
264 * 133 8/05/99 2:05a Dave
267 * 132 8/05/99 1:22a Andsager
270 * 131 8/04/99 9:51p Andsager
271 * Add title screen to demo
273 * 130 8/04/99 6:47p Jefff
274 * fixed link error resulting from #ifdefs
276 * 129 8/04/99 6:26p Dave
277 * Updated ship tbl checksum.
279 * 128 8/04/99 5:40p Andsager
280 * Add multiple demo dogs
282 * 127 8/04/99 5:36p Andsager
283 * Show upsell screens at end of demo campaign before returning to main
286 * 126 8/04/99 11:42a Danw
287 * tone down EAX reverb
289 * 125 8/04/99 11:23a Dave
290 * Updated demo checksums.
292 * 124 8/03/99 11:02p Dave
293 * Maybe fixed sync problems in multiplayer.
295 * 123 8/03/99 6:21p Jefff
298 * 122 8/03/99 3:44p Andsager
299 * Launch laucher if trying to run FS without first having configured
302 * 121 8/03/99 12:45p Dave
305 * 120 8/02/99 9:13p Dave
308 * 119 7/30/99 10:31p Dave
309 * Added comm menu to the configurable hud files.
311 * 118 7/30/99 5:17p Andsager
312 * first fs2demo checksums
314 * 117 7/29/99 3:09p Anoop
316 * 116 7/29/99 12:05a Dave
317 * Nebula speed optimizations.
319 * 115 7/27/99 8:59a Andsager
320 * Make major, minor version consistent for all builds. Only show major
321 * and minor for launcher update window.
323 * 114 7/26/99 5:50p Dave
324 * Revised ingame join. Better? We'll see....
326 * 113 7/26/99 5:27p Andsager
327 * Add training mission as builtin to demo build
329 * 112 7/24/99 1:54p Dave
330 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
333 * 111 7/22/99 4:00p Dave
334 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
336 * 110 7/21/99 8:10p Dave
337 * First run of supernova effect.
339 * 109 7/20/99 1:49p Dave
340 * Peter Drake build. Fixed some release build warnings.
342 * 108 7/19/99 2:26p Andsager
343 * set demo multiplayer missions
345 * 107 7/18/99 5:19p Dave
346 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
348 * 106 7/16/99 1:50p Dave
349 * 8 bit aabitmaps. yay.
351 * 105 7/15/99 3:07p Dave
352 * 32 bit detection support. Mouse coord commandline.
354 * 104 7/15/99 2:13p Dave
355 * Added 32 bit detection.
357 * 103 7/15/99 9:20a Andsager
358 * FS2_DEMO initial checkin
360 * 102 7/14/99 11:02a Dave
361 * Skill level default back to easy. Blech.
363 * 101 7/09/99 5:54p Dave
364 * Seperated cruiser types into individual types. Added tons of new
365 * briefing icons. Campaign screen.
367 * 100 7/08/99 4:43p Andsager
368 * New check for sparky_hi and print if not found.
370 * 99 7/08/99 10:53a Dave
371 * New multiplayer interpolation scheme. Not 100% done yet, but still
372 * better than the old way.
374 * 98 7/06/99 4:24p Dave
375 * Mid-level checkin. Starting on some potentially cool multiplayer
378 * 97 7/06/99 3:35p Andsager
379 * Allow movie to play before red alert mission.
381 * 96 7/03/99 5:50p Dave
382 * Make rotated bitmaps draw properly in padlock views.
384 * 95 7/02/99 9:55p Dave
385 * Player engine wash sound.
387 * 94 7/02/99 4:30p Dave
388 * Much more sophisticated lightning support.
390 * 93 6/29/99 7:52p Dave
391 * Put in exception handling in FS2.
393 * 92 6/22/99 9:37p Dave
394 * Put in pof spewing.
396 * 91 6/16/99 4:06p Dave
397 * New pilot info popup. Added new draw-bitmap-as-poly function.
399 * 90 6/15/99 1:56p Andsager
400 * For release builds, allow start up in high res only with
403 * 89 6/15/99 9:34a Dave
404 * Fixed key checking in single threaded version of the stamp notification
407 * 88 6/09/99 2:55p Andsager
408 * Allow multiple asteroid subtypes (of large, medium, small) and follow
411 * 87 6/08/99 1:14a Dave
412 * Multi colored hud test.
414 * 86 6/04/99 9:52a Dave
415 * Fixed some rendering problems.
417 * 85 6/03/99 10:15p Dave
418 * Put in temporary main hall screen.
420 * 84 6/02/99 6:18p Dave
421 * Fixed TNT lockup problems! Wheeeee!
423 * 83 6/01/99 3:52p Dave
424 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
425 * dead popup, pxo find player popup, pxo private room popup.
427 * 82 5/26/99 1:28p Jasenw
428 * changed coords for loading ani
430 * 81 5/26/99 11:46a Dave
431 * Added ship-blasting lighting and made the randomization of lighting
432 * much more customizable.
434 * 80 5/24/99 5:45p Dave
435 * Added detail levels to the nebula, with a decent speedup. Split nebula
436 * lightning into its own section.
454 #include "systemvars.h"
459 #include "starfield.h"
460 #include "lighting.h"
465 #include "fireballs.h"
469 #include "floating.h"
470 #include "gamesequence.h"
472 #include "optionsmenu.h"
473 #include "playermenu.h"
474 #include "trainingmenu.h"
475 #include "techmenu.h"
478 #include "hudmessage.h"
480 #include "missiongoals.h"
481 #include "missionparse.h"
486 #include "multiutil.h"
487 #include "multimsgs.h"
491 #include "freespace.h"
492 #include "managepilot.h"
494 #include "contexthelp.h"
497 #include "missionbrief.h"
498 #include "missiondebrief.h"
500 #include "missionshipchoice.h"
502 #include "hudconfig.h"
503 #include "controlsconfig.h"
504 #include "missionmessage.h"
505 #include "missiontraining.h"
507 #include "hudtarget.h"
511 #include "eventmusic.h"
512 #include "animplay.h"
513 #include "missionweaponchoice.h"
514 #include "missionlog.h"
515 #include "audiostr.h"
517 #include "missioncampaign.h"
519 #include "missionhotkey.h"
520 #include "objectsnd.h"
521 #include "cmeasure.h"
523 #include "linklist.h"
524 #include "shockwave.h"
525 #include "afterburner.h"
530 #include "stand_gui.h"
531 #include "pcxutils.h"
532 #include "hudtargetbox.h"
533 #include "multi_xfer.h"
534 #include "hudescort.h"
535 #include "multiutil.h"
538 #include "multiteamselect.h"
541 #include "readyroom.h"
542 #include "mainhallmenu.h"
543 #include "multilag.h"
545 #include "particle.h"
547 #include "multi_ingame.h"
548 #include "snazzyui.h"
549 #include "asteroid.h"
550 #include "popupdead.h"
551 #include "multi_voice.h"
552 #include "missioncmdbrief.h"
553 #include "redalert.h"
554 #include "gameplayhelp.h"
555 #include "multilag.h"
556 #include "staticrand.h"
557 #include "multi_pmsg.h"
558 #include "levelpaging.h"
559 #include "observer.h"
560 #include "multi_pause.h"
561 #include "multi_endgame.h"
562 #include "cutscenes.h"
563 #include "multi_respawn.h"
564 // #include "movie.h"
565 #include "multi_obj.h"
566 #include "multi_log.h"
568 #include "localize.h"
569 #include "osregistry.h"
570 #include "barracks.h"
571 #include "missionpause.h"
573 #include "alphacolors.h"
574 #include "objcollide.h"
577 #include "neblightning.h"
578 #include "shipcontrails.h"
581 #include "multi_dogfight.h"
582 #include "multi_rate.h"
583 #include "muzzleflash.h"
587 #include "mainhalltemp.h"
588 #include "exceptionhandler.h"
592 #include "supernova.h"
593 #include "hudshield.h"
594 // #include "names.h"
596 #include "missionloopbrief.h"
600 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
606 // 1.00.04 5/26/98 MWA -- going final (12 pm)
607 // 1.00.03 5/26/98 MWA -- going final (3 am)
608 // 1.00.02 5/25/98 MWA -- going final
609 // 1.00.01 5/25/98 MWA -- going final
610 // 0.90 5/21/98 MWA -- getting ready for final.
611 // 0.10 4/9/98. Set by MK.
613 // Demo version: (obsolete since DEMO codebase split from tree)
614 // 0.03 4/10/98 AL. Interplay rev
615 // 0.02 4/8/98 MK. Increased when this system was modified.
616 // 0.01 4/7/98? AL. First release to Interplay QA.
619 // 1.00 5/28/98 AL. First release to Interplay QA.
621 void game_level_init(int seed = -1);
622 void game_post_level_init();
623 void game_do_frame();
624 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
625 void game_reset_time();
626 void game_show_framerate(); // draws framerate in lower right corner
628 int Game_no_clear = 0;
630 int Pofview_running = 0;
631 int Nebedit_running = 0;
633 typedef struct big_expl_flash {
634 float max_flash_intensity; // max intensity
635 float cur_flash_intensity; // cur intensity
636 int flash_start; // start time
639 #define FRAME_FILTER 16
641 #define DEFAULT_SKILL_LEVEL 1
642 int Game_skill_level = DEFAULT_SKILL_LEVEL;
644 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
645 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
647 #define EXE_FNAME ("fs2.exe")
648 #define LAUNCHER_FNAME ("freespace2.exe")
650 // JAS: Code for warphole camera.
651 // Needs to be cleaned up.
652 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
653 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
654 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
655 matrix Camera_orient = IDENTITY_MATRIX;
656 float Camera_damping = 1.0f;
657 float Camera_time = 0.0f;
658 float Warpout_time = 0.0f;
659 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
660 int Warpout_sound = -1;
662 int Use_joy_mouse = 0;
663 int Use_palette_flash = 1;
665 int Use_fullscreen_at_startup = 0;
667 int Show_area_effect = 0;
668 object *Last_view_target = NULL;
670 int dogfight_blown = 0;
673 float frametimes[FRAME_FILTER];
674 float frametotal = 0.0f;
678 int Show_framerate = 0;
680 int Show_framerate = 1;
683 int Framerate_cap = 120;
686 int Show_target_debug_info = 0;
687 int Show_target_weapons = 0;
689 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
691 int Debug_octant = -1;
693 fix Game_time_compression = F1_0;
695 // if the ships.tbl the player has is valid
696 int Game_ships_tbl_valid = 0;
698 // if the weapons.tbl the player has is valid
699 int Game_weapons_tbl_valid = 0;
703 extern int Player_attacking_enabled;
707 int Pre_player_entry;
709 int Fred_running = 0;
710 char Game_current_mission_filename[MAX_FILENAME_LEN];
711 int game_single_step = 0;
712 int last_single_step=0;
714 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
715 extern int MSG_WINDOW_Y_START;
716 extern int MSG_WINDOW_HEIGHT;
718 int game_zbuffer = 1;
719 //static int Game_music_paused;
720 static int Game_paused;
724 #define EXPIRE_BAD_CHECKSUM 1
725 #define EXPIRE_BAD_TIME 2
727 extern void ssm_init();
728 extern void ssm_level_init();
729 extern void ssm_process();
731 // static variable to contain the time this version was built
732 // commented out for now until
733 // I figure out how to get the username into the file
734 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
736 // defines and variables used for dumping frame for making trailers.
738 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
739 int Debug_dump_trigger = 0;
740 int Debug_dump_frame_count;
741 int Debug_dump_frame_num = 0;
742 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
745 // amount of time to wait after the player has died before we display the death died popup
746 #define PLAYER_DIED_POPUP_WAIT 2500
747 int Player_died_popup_wait = -1;
748 int Player_multi_died_check = -1;
750 // builtin mission list stuff
752 int Game_builtin_mission_count = 6;
753 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
754 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
755 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
756 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
757 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
758 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
759 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
761 #elif defined(PD_BUILD)
762 int Game_builtin_mission_count = 4;
763 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
764 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
765 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
766 { "sm1-01", (FSB_FROM_VOLITION), "" },
767 { "sm1-05", (FSB_FROM_VOLITION), "" },
769 #elif defined(MULTIPLAYER_BETA)
770 int Game_builtin_mission_count = 17;
771 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
773 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
774 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
775 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
776 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
777 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
778 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
779 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
780 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
781 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
782 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
783 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
784 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
785 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
786 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
787 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
788 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
789 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
791 #elif defined(OEM_BUILD)
792 int Game_builtin_mission_count = 17;
793 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
794 // oem version - act 1 only
795 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
798 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
799 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
800 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
801 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
802 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
803 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
804 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
805 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
806 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
807 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
808 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
809 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
810 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
811 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
812 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
813 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
816 int Game_builtin_mission_count = 92;
817 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
818 // single player campaign
819 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
822 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
823 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
825 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
826 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
827 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
828 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
829 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
830 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
831 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
832 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
833 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
835 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
836 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
838 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
839 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
843 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
847 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
848 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
850 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
851 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
858 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
859 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
861 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
864 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
865 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
866 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
868 // multiplayer missions
871 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
925 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
926 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
927 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
928 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
933 // Internal function prototypes
934 void game_maybe_draw_mouse(float frametime);
935 void init_animating_pointer();
936 void load_animating_pointer(char *filename, int dx, int dy);
937 void unload_animating_pointer();
938 void game_do_training_checks();
939 void game_shutdown(void);
940 void game_show_event_debug(float frametime);
941 void game_event_debug_init();
943 void demo_upsell_show_screens();
944 void game_start_subspace_ambient_sound();
945 void game_stop_subspace_ambient_sound();
946 void verify_ships_tbl();
947 void verify_weapons_tbl();
948 void display_title_screen();
950 // loading background filenames
951 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
952 "LoadingBG", // GR_640
953 "2_LoadingBG" // GR_1024
957 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
958 "Loading.ani", // GR_640
959 "2_Loading.ani" // GR_1024
962 #if defined(FS2_DEMO)
963 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
967 #elif defined(OEM_BUILD)
968 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
975 char Game_CDROM_dir[MAX_PATH_LEN];
978 // How much RAM is on this machine. Set in WinMain
979 uint Freespace_total_ram = 0;
982 float Game_flash_red = 0.0f;
983 float Game_flash_green = 0.0f;
984 float Game_flash_blue = 0.0f;
985 float Sun_spot = 0.0f;
986 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
988 // game shudder stuff (in ms)
989 int Game_shudder_time = -1;
990 int Game_shudder_total = 0;
991 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
994 sound_env Game_sound_env;
995 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
996 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
998 int Game_sound_env_update_timestamp;
1000 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1003 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1005 fs_builtin_mission *game_find_builtin_mission(char *filename)
1009 // look through all existing builtin missions
1010 for(idx=0; idx<Game_builtin_mission_count; idx++){
1011 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1012 return &Game_builtin_mission_list[idx];
1020 int game_get_default_skill_level()
1022 return DEFAULT_SKILL_LEVEL;
1026 void game_flash_reset()
1028 Game_flash_red = 0.0f;
1029 Game_flash_green = 0.0f;
1030 Game_flash_blue = 0.0f;
1032 Big_expl_flash.max_flash_intensity = 0.0f;
1033 Big_expl_flash.cur_flash_intensity = 0.0f;
1034 Big_expl_flash.flash_start = 0;
1037 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1038 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1040 void game_framerate_check_init()
1042 // zero critical time
1043 Gf_critical_time = 0.0f;
1046 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1047 // if this is a glide card
1048 if(gr_screen.mode == GR_GLIDE){
1050 extern GrHwConfiguration hwconfig;
1053 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1054 Gf_critical = 15.0f;
1058 Gf_critical = 10.0f;
1063 Gf_critical = 15.0f;
1066 // d3d. only care about good cards here I guess (TNT)
1068 Gf_critical = 15.0f;
1071 // if this is a glide card
1072 if(gr_screen.mode == GR_GLIDE){
1074 extern GrHwConfiguration hwconfig;
1077 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1078 Gf_critical = 25.0f;
1082 Gf_critical = 20.0f;
1087 Gf_critical = 25.0f;
1090 // d3d. only care about good cards here I guess (TNT)
1092 Gf_critical = 25.0f;
1097 extern float Framerate;
1098 void game_framerate_check()
1102 // if the current framerate is above the critical level, add frametime
1103 if(Framerate >= Gf_critical){
1104 Gf_critical_time += flFrametime;
1107 if(!Show_framerate){
1111 // display if we're above the critical framerate
1112 if(Framerate < Gf_critical){
1113 gr_set_color_fast(&Color_bright_red);
1114 gr_string(200, y_start, "Framerate warning");
1119 // display our current pct of good frametime
1120 if(f2fl(Missiontime) >= 0.0f){
1121 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1124 gr_set_color_fast(&Color_bright_green);
1126 gr_set_color_fast(&Color_bright_red);
1129 gr_printf(200, y_start, "%d%%", (int)pct);
1136 // Adds a flash effect. These can be positive or negative.
1137 // The range will get capped at around -1 to 1, so stick
1138 // with a range like that.
1139 void game_flash( float r, float g, float b )
1141 Game_flash_red += r;
1142 Game_flash_green += g;
1143 Game_flash_blue += b;
1145 if ( Game_flash_red < -1.0f ) {
1146 Game_flash_red = -1.0f;
1147 } else if ( Game_flash_red > 1.0f ) {
1148 Game_flash_red = 1.0f;
1151 if ( Game_flash_green < -1.0f ) {
1152 Game_flash_green = -1.0f;
1153 } else if ( Game_flash_green > 1.0f ) {
1154 Game_flash_green = 1.0f;
1157 if ( Game_flash_blue < -1.0f ) {
1158 Game_flash_blue = -1.0f;
1159 } else if ( Game_flash_blue > 1.0f ) {
1160 Game_flash_blue = 1.0f;
1165 // Adds a flash for Big Ship explosions
1166 // cap range from 0 to 1
1167 void big_explosion_flash(float flash)
1169 Big_expl_flash.flash_start = timestamp(1);
1173 } else if (flash < 0.0f) {
1177 Big_expl_flash.max_flash_intensity = flash;
1178 Big_expl_flash.cur_flash_intensity = 0.0f;
1181 // Amount to diminish palette towards normal, per second.
1182 #define DIMINISH_RATE 0.75f
1183 #define SUN_DIMINISH_RATE 6.00f
1187 float sn_glare_scale = 1.7f;
1190 dc_get_arg(ARG_FLOAT);
1191 sn_glare_scale = Dc_arg_float;
1194 float Supernova_last_glare = 0.0f;
1195 void game_sunspot_process(float frametime)
1199 float Sun_spot_goal = 0.0f;
1202 sn_stage = supernova_active();
1204 // sunspot differently based on supernova stage
1206 // approaching. player still in control
1209 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1212 light_get_global_dir(&light_dir, 0);
1214 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1217 // scale it some more
1218 dot = dot * (0.5f + (pct * 0.5f));
1221 Sun_spot_goal += (dot * sn_glare_scale);
1224 // draw the sun glow
1225 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1226 // draw the glow for this sun
1227 stars_draw_sun_glow(0);
1230 Supernova_last_glare = Sun_spot_goal;
1233 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1236 Sun_spot_goal = 0.9f;
1237 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1239 if(Sun_spot_goal > 1.0f){
1240 Sun_spot_goal = 1.0f;
1243 Sun_spot_goal *= sn_glare_scale;
1244 Supernova_last_glare = Sun_spot_goal;
1247 // fade to white. display dead popup
1250 Supernova_last_glare += (2.0f * flFrametime);
1251 if(Supernova_last_glare > 2.0f){
1252 Supernova_last_glare = 2.0f;
1255 Sun_spot_goal = Supernova_last_glare;
1262 // check sunspots for all suns
1263 n_lights = light_get_global_count();
1266 for(idx=0; idx<n_lights; idx++){
1267 //(vector *eye_pos, matrix *eye_orient)
1268 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1271 light_get_global_dir(&light_dir, idx);
1273 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1275 Sun_spot_goal += (float)pow(dot,85.0f);
1277 // draw the glow for this sun
1278 stars_draw_sun_glow(idx);
1280 Sun_spot_goal = 0.0f;
1286 Sun_spot_goal = 0.0f;
1290 float dec_amount = frametime*SUN_DIMINISH_RATE;
1292 if ( Sun_spot < Sun_spot_goal ) {
1293 Sun_spot += dec_amount;
1294 if ( Sun_spot > Sun_spot_goal ) {
1295 Sun_spot = Sun_spot_goal;
1297 } else if ( Sun_spot > Sun_spot_goal ) {
1298 Sun_spot -= dec_amount;
1299 if ( Sun_spot < Sun_spot_goal ) {
1300 Sun_spot = Sun_spot_goal;
1306 // Call once a frame to diminish the
1307 // flash effect to 0.
1308 void game_flash_diminish(float frametime)
1310 float dec_amount = frametime*DIMINISH_RATE;
1312 if ( Game_flash_red > 0.0f ) {
1313 Game_flash_red -= dec_amount;
1314 if ( Game_flash_red < 0.0f )
1315 Game_flash_red = 0.0f;
1317 Game_flash_red += dec_amount;
1318 if ( Game_flash_red > 0.0f )
1319 Game_flash_red = 0.0f;
1322 if ( Game_flash_green > 0.0f ) {
1323 Game_flash_green -= dec_amount;
1324 if ( Game_flash_green < 0.0f )
1325 Game_flash_green = 0.0f;
1327 Game_flash_green += dec_amount;
1328 if ( Game_flash_green > 0.0f )
1329 Game_flash_green = 0.0f;
1332 if ( Game_flash_blue > 0.0f ) {
1333 Game_flash_blue -= dec_amount;
1334 if ( Game_flash_blue < 0.0f )
1335 Game_flash_blue = 0.0f;
1337 Game_flash_blue += dec_amount;
1338 if ( Game_flash_blue > 0.0f )
1339 Game_flash_blue = 0.0f;
1342 // update big_explosion_cur_flash
1343 #define TIME_UP 1500
1344 #define TIME_DOWN 2500
1345 int duration = TIME_UP + TIME_DOWN;
1346 int time = timestamp_until(Big_expl_flash.flash_start);
1347 if (time > -duration) {
1349 if (time < TIME_UP) {
1350 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1353 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1357 if ( Use_palette_flash ) {
1359 // static int or=0, og=0, ob=0;
1361 // Change the 200 to change the color range of colors.
1362 r = fl2i( Game_flash_red*128.0f );
1363 g = fl2i( Game_flash_green*128.0f );
1364 b = fl2i( Game_flash_blue*128.0f );
1366 if ( Sun_spot > 0.0f ) {
1367 r += fl2i(Sun_spot*128.0f);
1368 g += fl2i(Sun_spot*128.0f);
1369 b += fl2i(Sun_spot*128.0f);
1372 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1373 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1374 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1375 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1378 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1379 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1380 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1382 if ( (r!=0) || (g!=0) || (b!=0) ) {
1383 gr_flash( r, g, b );
1385 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1396 void game_level_close()
1398 // De-Initialize the game subsystems
1399 message_mission_shutdown();
1400 event_music_level_close();
1401 game_stop_looped_sounds();
1403 obj_snd_level_close(); // uninit object-linked persistant sounds
1404 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1405 anim_level_close(); // stop and clean up any anim instances
1406 shockwave_level_close();
1407 fireball_level_close();
1409 mission_event_shutdown();
1410 asteroid_level_close();
1411 model_cache_reset(); // Reset/free all the model caching stuff
1412 flak_level_close(); // unload flak stuff
1413 neb2_level_close(); // shutdown gaseous nebula stuff
1416 mflash_level_close();
1418 audiostream_unpause_all();
1423 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1424 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1425 void game_level_init(int seed)
1427 // seed the random number generator
1429 // if no seed was passed, seed the generator either from the time value, or from the
1430 // netgame security flags -- ensures that all players in multiplayer game will have the
1431 // same randon number sequence (with static rand functions)
1432 if ( Game_mode & GM_NORMAL ) {
1433 Game_level_seed = time(NULL);
1435 Game_level_seed = Netgame.security;
1438 // mwa 9/17/98 -- maybe this assert isn't needed????
1439 Assert( !(Game_mode & GM_MULTIPLAYER) );
1440 Game_level_seed = seed;
1442 srand( Game_level_seed );
1444 // semirand function needs to get re-initted every time in multiplayer
1445 if ( Game_mode & GM_MULTIPLAYER ){
1451 Key_normal_game = (Game_mode & GM_NORMAL);
1454 Game_shudder_time = -1;
1456 // Initialize the game subsystems
1457 // timestamp_reset(); // Must be inited before everything else
1459 game_reset_time(); // resets time, and resets saved time too
1461 obj_init(); // Must be inited before the other systems
1462 model_free_all(); // Free all existing models
1463 mission_brief_common_init(); // Free all existing briefing/debriefing text
1464 weapon_level_init();
1465 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1467 player_level_init();
1468 shipfx_flash_init(); // Init the ship gun flash system.
1469 game_flash_reset(); // Reset the flash effect
1470 particle_init(); // Reset the particle system
1474 shield_hit_init(); // Initialize system for showing shield hits
1475 radar_mission_init();
1476 mission_init_goals();
1479 obj_snd_level_init(); // init object-linked persistant sounds
1481 shockwave_level_init();
1482 afterburner_level_init();
1483 scoring_level_init( &Player->stats );
1485 asteroid_level_init();
1486 control_config_clear_used_status();
1487 collide_ship_ship_sounds_init();
1489 Pre_player_entry = 1; // Means the player has not yet entered.
1490 Entry_delay_time = 0; // Could get overwritten in mission read.
1491 fireball_preload(); // page in warphole bitmaps
1493 flak_level_init(); // initialize flak - bitmaps, etc
1494 ct_level_init(); // initialize ships contrails, etc
1495 awacs_level_init(); // initialize AWACS
1496 beam_level_init(); // initialize beam weapons
1497 mflash_level_init();
1499 supernova_level_init();
1501 // multiplayer dogfight hack
1504 shipfx_engine_wash_level_init();
1508 Last_view_target = NULL;
1513 // campaign wasn't ended
1514 Campaign_ended_in_mission = 0;
1517 // called when a mission is over -- does server specific stuff.
1518 void freespace_stop_mission()
1521 Game_mode &= ~GM_IN_MISSION;
1524 // called at frame interval to process networking stuff
1525 void game_do_networking()
1527 Assert( Net_player != NULL );
1528 if (!(Game_mode & GM_MULTIPLAYER)){
1532 // see if this player should be reading/writing data. Bit is set when at join
1533 // screen onward until quits back to main menu.
1534 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1538 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1541 multi_pause_do_frame();
1546 // Loads the best palette for this level, based
1547 // on nebula color and hud color. You could just call palette_load_table with
1548 // the appropriate filename, but who wants to do that.
1549 void game_load_palette()
1551 char palette_filename[1024];
1553 // We only use 3 hud colors right now
1554 // Assert( HUD_config.color >= 0 );
1555 // Assert( HUD_config.color <= 2 );
1557 Assert( Mission_palette >= 0 );
1558 Assert( Mission_palette <= 98 );
1560 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1561 strcpy( palette_filename, NOX("gamepalette-subspace") );
1563 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1566 mprintf(( "Loading palette %s\n", palette_filename ));
1568 // palette_load_table(palette_filename);
1571 void game_post_level_init()
1573 // Stuff which gets called after mission is loaded. Because player isn't created until
1574 // after mission loads, some things must get initted after the level loads
1576 model_level_post_init();
1579 hud_setup_escort_list();
1580 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1586 game_event_debug_init();
1589 training_mission_init();
1590 asteroid_create_all();
1592 game_framerate_check_init();
1596 // An estimate as to how high the count passed to game_loading_callback will go.
1597 // This is just a guess, it seems to always be about the same. The count is
1598 // proportional to the code being executed, not the time, so this works good
1599 // for a bar, assuming the code does about the same thing each time you
1600 // load a level. You can find this value by looking at the return value
1601 // of game_busy_callback(NULL), which I conveniently print out to the
1602 // debug output window with the '=== ENDING LOAD ==' stuff.
1603 //#define COUNT_ESTIMATE 3706
1604 #define COUNT_ESTIMATE 1111
1606 int Game_loading_callback_inited = 0;
1608 int Game_loading_background = -1;
1609 anim * Game_loading_ani = NULL;
1610 anim_instance *Game_loading_ani_instance;
1611 int Game_loading_frame=-1;
1613 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1622 // This gets called 10x per second and count is the number of times
1623 // game_busy() has been called since the current callback function
1625 void game_loading_callback(int count)
1627 game_do_networking();
1629 Assert( Game_loading_callback_inited==1 );
1630 Assert( Game_loading_ani != NULL );
1632 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1633 if ( framenum > Game_loading_ani->total_frames-1 ) {
1634 framenum = Game_loading_ani->total_frames-1;
1635 } else if ( framenum < 0 ) {
1640 while ( Game_loading_frame < framenum ) {
1641 Game_loading_frame++;
1642 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1646 if ( cbitmap > -1 ) {
1647 if ( Game_loading_background > -1 ) {
1648 gr_set_bitmap( Game_loading_background );
1652 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1653 gr_set_bitmap( cbitmap );
1654 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1656 bm_release(cbitmap);
1662 void game_loading_callback_init()
1664 Assert( Game_loading_callback_inited==0 );
1666 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1667 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1670 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1671 Assert( Game_loading_ani != NULL );
1672 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1673 Assert( Game_loading_ani_instance != NULL );
1674 Game_loading_frame = -1;
1676 Game_loading_callback_inited = 1;
1678 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1683 void game_loading_callback_close()
1685 Assert( Game_loading_callback_inited==1 );
1687 // Make sure bar shows all the way over.
1688 game_loading_callback(COUNT_ESTIMATE);
1690 int real_count = game_busy_callback( NULL );
1693 Game_loading_callback_inited = 0;
1696 mprintf(( "=================== ENDING LOAD ================\n" ));
1697 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1698 mprintf(( "================================================\n" ));
1700 // to remove warnings in release build
1704 free_anim_instance(Game_loading_ani_instance);
1705 Game_loading_ani_instance = NULL;
1706 anim_free(Game_loading_ani);
1707 Game_loading_ani = NULL;
1709 bm_release( Game_loading_background );
1710 common_free_interface_palette(); // restore game palette
1711 Game_loading_background = -1;
1713 gr_set_font( FONT1 );
1716 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1718 void game_maybe_update_sound_environment()
1720 // do nothing for now
1723 // Assign the sound environment for the game, based on the current mission
1725 void game_assign_sound_environment()
1728 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1729 Game_sound_env.id = SND_ENV_DRUGGED;
1730 Game_sound_env.volume = 0.800f;
1731 Game_sound_env.damping = 1.188f;
1732 Game_sound_env.decay = 6.392f;
1734 } else if (Num_asteroids > 30) {
1735 Game_sound_env.id = SND_ENV_AUDITORIUM;
1736 Game_sound_env.volume = 0.603f;
1737 Game_sound_env.damping = 0.5f;
1738 Game_sound_env.decay = 4.279f;
1741 Game_sound_env = Game_default_sound_env;
1745 Game_sound_env = Game_default_sound_env;
1746 Game_sound_env_update_timestamp = timestamp(1);
1749 // function which gets called before actually entering the mission. It is broken down into a funciton
1750 // since it will get called in one place from a single player game and from another place for
1751 // a multiplayer game
1752 void freespace_mission_load_stuff()
1754 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1755 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1756 if(!(Game_mode & GM_STANDALONE_SERVER)){
1758 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1760 game_loading_callback_init();
1762 event_music_level_init(); // preloads the first 2 seconds for each event music track
1765 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1768 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1771 ship_assign_sound_all(); // assign engine sounds to ships
1772 game_assign_sound_environment(); // assign the sound environment for this mission
1775 // call function in missionparse.cpp to fixup player/ai stuff.
1776 mission_parse_fixup_players();
1779 // Load in all the bitmaps for this level
1784 game_loading_callback_close();
1786 // the only thing we need to call on the standalone for now.
1788 // call function in missionparse.cpp to fixup player/ai stuff.
1789 mission_parse_fixup_players();
1791 // Load in all the bitmaps for this level
1797 uint load_mission_load;
1798 uint load_post_level_init;
1799 uint load_mission_stuff;
1801 // tells the server to load the mission and initialize structures
1802 int game_start_mission()
1804 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1806 load_gl_init = time(NULL);
1808 load_gl_init = time(NULL) - load_gl_init;
1810 if (Game_mode & GM_MULTIPLAYER) {
1811 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1813 // clear multiplayer stats
1814 init_multiplayer_stats();
1817 load_mission_load = time(NULL);
1818 if (mission_load()) {
1819 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1820 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1821 gameseq_post_event(GS_EVENT_MAIN_MENU);
1823 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1828 load_mission_load = time(NULL) - load_mission_load;
1830 // If this is a red alert mission in campaign mode, bash wingman status
1831 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1832 red_alert_bash_wingman_status();
1835 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1836 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1837 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1838 // game_load_palette();
1841 load_post_level_init = time(NULL);
1842 game_post_level_init();
1843 load_post_level_init = time(NULL) - load_post_level_init;
1847 void Do_model_timings_test();
1848 Do_model_timings_test();
1852 load_mission_stuff = time(NULL);
1853 freespace_mission_load_stuff();
1854 load_mission_stuff = time(NULL) - load_mission_stuff;
1859 int Interface_framerate = 0;
1862 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1863 DCF_BOOL( show_framerate, Show_framerate )
1864 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1865 DCF_BOOL( show_target_weapons, Show_target_weapons )
1866 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1867 DCF_BOOL( sound, Sound_enabled )
1868 DCF_BOOL( zbuffer, game_zbuffer )
1869 DCF_BOOL( shield_system, New_shield_system )
1870 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1871 DCF_BOOL( player_attacking, Player_attacking_enabled )
1872 DCF_BOOL( show_waypoints, Show_waypoints )
1873 DCF_BOOL( show_area_effect, Show_area_effect )
1874 DCF_BOOL( show_net_stats, Show_net_stats )
1875 DCF_BOOL( log, Log_debug_output_to_file )
1876 DCF_BOOL( training_msg_method, Training_msg_method )
1877 DCF_BOOL( show_player_pos, Show_player_pos )
1878 DCF_BOOL(i_framerate, Interface_framerate )
1880 DCF(show_mem,"Toggles showing mem usage")
1883 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1884 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1885 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1886 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1892 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1894 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1895 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1899 DCF(show_cpu,"Toggles showing cpu usage")
1902 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1903 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1904 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1905 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1911 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1913 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1914 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1921 // AL 4-8-98: always allow players to display their framerate
1924 DCF_BOOL( show_framerate, Show_framerate )
1931 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1934 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1935 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1936 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1937 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1939 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" );
1940 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1942 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1945 DCF(palette_flash,"Toggles palette flash effect on/off")
1948 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1949 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1950 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1951 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1953 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1954 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1957 int Use_low_mem = 0;
1959 DCF(low_mem,"Uses low memory settings regardless of RAM")
1962 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1963 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1964 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1965 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1967 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1968 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1970 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1976 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1979 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1980 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1981 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1982 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1984 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1985 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1986 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1990 int Framerate_delay = 0;
1992 float Freespace_gamma = 1.0f;
1994 DCF(gamma,"Sets Gamma factor")
1997 dc_get_arg(ARG_FLOAT|ARG_NONE);
1998 if ( Dc_arg_type & ARG_FLOAT ) {
1999 Freespace_gamma = Dc_arg_float;
2001 dc_printf( "Gamma reset to 1.0f\n" );
2002 Freespace_gamma = 1.0f;
2004 if ( Freespace_gamma < 0.1f ) {
2005 Freespace_gamma = 0.1f;
2006 } else if ( Freespace_gamma > 5.0f ) {
2007 Freespace_gamma = 5.0f;
2009 gr_set_gamma(Freespace_gamma);
2011 char tmp_gamma_string[32];
2012 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2013 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2017 dc_printf( "Usage: gamma <float>\n" );
2018 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2019 Dc_status = 0; // don't print status if help is printed. Too messy.
2023 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2032 Game_current_mission_filename[0] = 0;
2034 // seed the random number generator
2035 Game_init_seed = time(NULL);
2036 srand( Game_init_seed );
2038 Framerate_delay = 0;
2044 extern void bm_init();
2050 // Initialize the timer before the os
2058 GetCurrentDirectory(1024, whee);
2061 getcwd (whee, 1024);
2064 strcat(whee, EXE_FNAME);
2066 //Initialize the libraries
2067 s1 = timer_get_milliseconds();
2068 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2071 e1 = timer_get_milliseconds();
2073 // time a bunch of cfopens
2075 s2 = timer_get_milliseconds();
2077 for(int idx=0; idx<10000; idx++){
2078 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2083 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2085 e2 = timer_get_milliseconds();
2088 if (Is_standalone) {
2089 std_init_standalone();
2091 os_init( Osreg_class_name, Osreg_app_name );
2092 os_set_title(Osreg_title);
2095 // initialize localization module. Make sure this is down AFTER initialzing OS.
2096 // int t1 = timer_get_milliseconds();
2099 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2101 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2104 // verify that he has a valid weapons.tbl
2105 verify_weapons_tbl();
2107 // Output version numbers to registry for auto patching purposes
2108 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2109 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2110 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2112 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2113 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2114 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2117 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2121 Asteroids_enabled = 1;
2124 /////////////////////////////
2126 /////////////////////////////
2131 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2132 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2134 if (!stricmp(ptr, NOX("no sound"))) {
2135 Cmdline_freespace_no_sound = 1;
2137 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2139 } else if (!stricmp(ptr, NOX("EAX"))) {
2144 if (!Is_standalone) {
2145 snd_init(use_a3d, use_eax);
2147 /////////////////////////////
2149 /////////////////////////////
2151 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2154 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);
2156 // fire up the UpdateLauncher executable
2158 PROCESS_INFORMATION pi;
2160 memset( &si, 0, sizeof(STARTUPINFO) );
2163 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2164 NULL, // pointer to command line string
2165 NULL, // pointer to process security attributes
2166 NULL, // pointer to thread security attributes
2167 FALSE, // handle inheritance flag
2168 CREATE_DEFAULT_ERROR_MODE, // creation flags
2169 NULL, // pointer to new environment block
2170 NULL, // pointer to current directory name
2171 &si, // pointer to STARTUPINFO
2172 &pi // pointer to PROCESS_INFORMATION
2175 // If the Launcher could not be started up, let the user know
2177 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2186 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2188 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);
2196 // check for hi res pack file
2197 int has_sparky_hi = 0;
2199 // check if sparky_hi exists -- access mode 0 means does file exist
2202 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2205 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2208 // see if we've got 32 bit in the string
2209 if(strstr(ptr, "32 bit")){
2215 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2217 // always 640 for E3
2218 gr_init(GR_640, GR_GLIDE);
2220 // regular or hi-res ?
2222 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2224 if(strstr(ptr, NOX("(1024x768)"))){
2226 gr_init(GR_1024, GR_GLIDE);
2228 gr_init(GR_640, GR_GLIDE);
2231 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2233 // always 640 for E3
2235 gr_init(GR_640, GR_DIRECT3D, depth);
2237 // regular or hi-res ?
2239 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2241 if(strstr(ptr, NOX("(1024x768)"))){
2245 gr_init(GR_1024, GR_DIRECT3D, depth);
2249 gr_init(GR_640, GR_DIRECT3D, depth);
2255 if ( Use_fullscreen_at_startup && !Is_standalone) {
2256 gr_init(GR_640, GR_DIRECTDRAW);
2259 gr_init(GR_640, GR_OPENGL);
2261 gr_init(GR_640, GR_SOFTWARE);
2265 if ( !Is_standalone ) {
2266 gr_init(GR_640, GR_DIRECTDRAW);
2269 gr_init(GR_640, GR_OPENGL);
2271 gr_init(GR_640, GR_SOFTWAREL);
2278 extern int Gr_inited;
2279 if(trying_d3d && !Gr_inited){
2280 extern char Device_init_error[512];
2282 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2291 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2292 Freespace_gamma = (float)atof(ptr);
2293 if ( Freespace_gamma == 0.0f ) {
2294 Freespace_gamma = 1.80f;
2295 } else if ( Freespace_gamma < 0.1f ) {
2296 Freespace_gamma = 0.1f;
2297 } else if ( Freespace_gamma > 5.0f ) {
2298 Freespace_gamma = 5.0f;
2300 char tmp_gamma_string[32];
2301 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2302 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2304 gr_set_gamma(Freespace_gamma);
2306 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2309 display_title_screen();
2313 // attempt to load up master tracker registry info (login and password)
2314 Multi_tracker_id = -1;
2316 // pxo login and password
2317 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2319 nprintf(("Network","Error reading in PXO login data\n"));
2320 strcpy(Multi_tracker_login,"");
2322 strcpy(Multi_tracker_login,ptr);
2324 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2326 nprintf(("Network","Error reading PXO password\n"));
2327 strcpy(Multi_tracker_passwd,"");
2329 strcpy(Multi_tracker_passwd,ptr);
2332 // pxo squad name and password
2333 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2335 nprintf(("Network","Error reading in PXO squad name\n"));
2336 strcpy(Multi_tracker_squad_name, "");
2338 strcpy(Multi_tracker_squad_name, ptr);
2341 // If less than 48MB of RAM, use low memory model.
2342 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2343 mprintf(( "Using normal memory settings...\n" ));
2344 bm_set_low_mem(1); // Use every other frame of bitmaps
2346 mprintf(( "Using high memory settings...\n" ));
2347 bm_set_low_mem(0); // Use all frames of bitmaps
2350 // load non-darkening pixel defs
2351 palman_load_pixels();
2353 // hud shield icon stuff
2354 hud_shield_game_init();
2356 control_config_common_init(); // sets up localization stuff in the control config
2362 gamesnd_parse_soundstbl();
2367 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2372 player_controls_init();
2375 //if(!Is_standalone){
2383 ship_init(); // read in ships.tbl
2385 mission_campaign_init(); // load in the default campaign
2387 // navmap_init(); // init the navigation map system
2388 context_help_init();
2389 techroom_intel_init(); // parse species.tbl, load intel info
2391 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2392 init_animating_pointer();
2394 mission_brief_common_init(); // Mark all the briefing structures as empty.
2395 gr_font_init(); // loads up all fonts
2397 neb2_init(); // fullneb stuff
2401 player_tips_init(); // helpful tips
2404 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2405 pilot_load_pic_list();
2406 pilot_load_squad_pic_list();
2408 load_animating_pointer(NOX("cursor"), 0, 0);
2410 // initialize alpha colors
2411 alpha_colors_init();
2414 // Game_music_paused = 0;
2421 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2422 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2424 mprintf(("cfile_init() took %d\n", e1 - s1));
2425 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2428 char transfer_text[128];
2430 float Start_time = 0.0f;
2432 float Framerate = 0.0f;
2434 float Timing_total = 0.0f;
2435 float Timing_render2 = 0.0f;
2436 float Timing_render3 = 0.0f;
2437 float Timing_flip = 0.0f;
2438 float Timing_clear = 0.0f;
2440 MONITOR(NumPolysDrawn);
2446 void game_get_framerate()
2448 char text[128] = "";
2450 if ( frame_int == -1 ) {
2452 for (i=0; i<FRAME_FILTER; i++ ) {
2453 frametimes[i] = 0.0f;
2458 frametotal -= frametimes[frame_int];
2459 frametotal += flFrametime;
2460 frametimes[frame_int] = flFrametime;
2461 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2463 if ( frametotal != 0.0 ) {
2464 if ( Framecount >= FRAME_FILTER )
2465 Framerate = FRAME_FILTER / frametotal;
2467 Framerate = Framecount / frametotal;
2468 sprintf( text, NOX("FPS: %.1f"), Framerate );
2470 sprintf( text, NOX("FPS: ?") );
2474 if (Show_framerate) {
2475 gr_set_color_fast(&HUD_color_debug);
2476 gr_string( 570, 2, text );
2480 void game_show_framerate()
2484 cur_time = f2fl(timer_get_approx_seconds());
2485 if (cur_time - Start_time > 30.0f) {
2486 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2487 Start_time += 1000.0f;
2490 //mprintf(( "%s\n", text ));
2493 if ( Debug_dump_frames )
2497 // possibly show control checking info
2498 control_check_indicate();
2500 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2501 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2502 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2503 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2506 if ( Show_cpu == 1 ) {
2511 dy = gr_get_font_height() + 1;
2513 gr_set_color_fast(&HUD_color_debug);
2517 extern int D3D_textures_in;
2518 extern int D3D_textures_in_frame;
2519 extern int Glide_textures_in;
2520 extern int Glide_textures_in_frame;
2521 extern int Glide_explosion_vram;
2522 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2524 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2526 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2532 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2534 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2536 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2538 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2540 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2545 extern int Num_pairs; // Number of object pairs that were checked.
2546 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2549 extern int Num_pairs_checked; // What percent of object pairs were checked.
2550 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2552 Num_pairs_checked = 0;
2556 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2559 if ( Timing_total > 0.01f ) {
2560 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2562 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2564 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2566 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2568 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2578 dy = gr_get_font_height() + 1;
2580 gr_set_color_fast(&HUD_color_debug);
2583 extern int TotalRam;
2584 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2589 extern int Model_ram;
2590 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2594 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2596 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2598 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2602 extern int D3D_textures_in;
2603 extern int Glide_textures_in;
2604 extern int Glide_textures_in_frame;
2605 extern int Glide_explosion_vram;
2606 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2608 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2610 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2619 if ( Show_player_pos ) {
2623 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));
2626 MONITOR_INC(NumPolys, modelstats_num_polys);
2627 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2628 MONITOR_INC(NumVerts, modelstats_num_verts );
2630 modelstats_num_polys = 0;
2631 modelstats_num_polys_drawn = 0;
2632 modelstats_num_verts = 0;
2633 modelstats_num_sortnorms = 0;
2637 void game_show_standalone_framerate()
2639 float frame_rate=30.0f;
2640 if ( frame_int == -1 ) {
2642 for (i=0; i<FRAME_FILTER; i++ ) {
2643 frametimes[i] = 0.0f;
2648 frametotal -= frametimes[frame_int];
2649 frametotal += flFrametime;
2650 frametimes[frame_int] = flFrametime;
2651 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2653 if ( frametotal != 0.0 ) {
2654 if ( Framecount >= FRAME_FILTER ){
2655 frame_rate = FRAME_FILTER / frametotal;
2657 frame_rate = Framecount / frametotal;
2660 std_set_standalone_fps(frame_rate);
2664 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2665 void game_show_time_left()
2669 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2670 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2671 // checking how much time is left
2673 if ( Mission_end_time == -1 ){
2677 diff = f2i(Mission_end_time - Missiontime);
2678 // be sure to bash to 0. diff could be negative on frame that we quit mission
2683 hud_set_default_color();
2684 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2687 //========================================================================================
2688 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2689 //========================================================================================
2693 DCF(ai_pause,"Pauses ai")
2696 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2697 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2698 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2699 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2702 obj_init_all_ships_physics();
2705 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2706 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2709 DCF(single_step,"Single steps the game")
2712 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2713 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2714 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2715 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2717 last_single_step = 0; // Make so single step waits a frame before stepping
2720 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2721 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2724 DCF_BOOL(physics_pause, physics_paused)
2725 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2726 DCF_BOOL(ai_firing, Ai_firing_enabled )
2728 // Create some simple aliases to these commands...
2729 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2730 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2731 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2732 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2733 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2736 //========================================================================================
2737 //========================================================================================
2740 void game_training_pause_do()
2744 key = game_check_key();
2746 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2753 void game_increase_skill_level()
2756 if (Game_skill_level >= NUM_SKILL_LEVELS){
2757 Game_skill_level = 0;
2761 int Player_died_time;
2763 int View_percent = 100;
2766 DCF(view, "Sets the percent of the 3d view to render.")
2769 dc_get_arg(ARG_INT);
2770 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2771 View_percent = Dc_arg_int;
2773 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2779 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2783 dc_printf("View is set to %d%%\n", View_percent );
2788 // Set the clip region for the 3d rendering window
2789 void game_set_view_clip()
2791 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2792 // Set the clip region for the letterbox "dead view"
2793 int yborder = gr_screen.max_h/4;
2795 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2796 // J.S. I've changed my ways!! See the new "no constants" code!!!
2797 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2799 // Set the clip region for normal view
2800 if ( View_percent >= 100 ) {
2803 int xborder, yborder;
2805 if ( View_percent < 5 ) {
2809 float fp = i2fl(View_percent)/100.0f;
2810 int fi = fl2i(fl_sqrt(fp)*100.0f);
2811 if ( fi > 100 ) fi=100;
2813 xborder = ( gr_screen.max_w*(100-fi) )/200;
2814 yborder = ( gr_screen.max_h*(100-fi) )/200;
2816 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2822 void show_debug_stuff()
2825 int laser_count = 0, missile_count = 0;
2827 for (i=0; i<MAX_OBJECTS; i++) {
2828 if (Objects[i].type == OBJ_WEAPON){
2829 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2831 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2837 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2840 extern int Tool_enabled;
2845 int tst_bitmap = -1;
2847 float tst_offset, tst_offset_total;
2850 void game_tst_frame_pre()
2858 g3_rotate_vertex(&v, &tst_pos);
2859 g3_project_vertex(&v);
2862 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2866 // big ship? always tst
2868 // within 3000 meters
2869 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2873 // within 300 meters
2874 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2881 void game_tst_frame()
2891 tst_time = time(NULL);
2893 // load the tst bitmap
2894 switch((int)frand_range(0.0f, 3.0)){
2896 tst_bitmap = bm_load("ig_jim");
2898 mprintf(("TST 0\n"));
2902 tst_bitmap = bm_load("ig_kan");
2904 mprintf(("TST 1\n"));
2908 tst_bitmap = bm_load("ig_jim");
2910 mprintf(("TST 2\n"));
2914 tst_bitmap = bm_load("ig_kan");
2916 mprintf(("TST 3\n"));
2925 // get the tst bitmap dimensions
2927 bm_get_info(tst_bitmap, &w, &h);
2930 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2932 snd_play(&Snds[SND_VASUDAN_BUP]);
2934 // tst x and direction
2938 tst_offset_total = (float)w;
2939 tst_offset = (float)w;
2941 tst_x = (float)gr_screen.max_w;
2942 tst_offset_total = (float)-w;
2943 tst_offset = (float)w;
2951 float diff = (tst_offset_total / 0.5f) * flFrametime;
2957 tst_offset -= fl_abs(diff);
2958 } else if(tst_mode == 2){
2961 tst_offset -= fl_abs(diff);
2965 gr_set_bitmap(tst_bitmap);
2966 gr_bitmap((int)tst_x, (int)tst_y);
2969 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2973 // if we passed the switch point
2974 if(tst_offset <= 0.0f){
2979 tst_stamp = timestamp(1000);
2980 tst_offset = fl_abs(tst_offset_total);
2991 void game_tst_mark(object *objp, ship *shipp)
3000 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3003 sip = &Ship_info[shipp->ship_info_index];
3010 tst_pos = objp->pos;
3011 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3017 extern void render_shields();
3019 void player_repair_frame(float frametime)
3021 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3023 for(idx=0;idx<MAX_PLAYERS;idx++){
3026 np = &Net_players[idx];
3028 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)){
3030 // don't rearm/repair if the player is dead or dying/departing
3031 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3032 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3037 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3038 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3044 #define NUM_FRAMES_TEST 300
3045 #define NUM_MIXED_SOUNDS 16
3046 void do_timing_test(float flFrametime)
3048 static int framecount = 0;
3049 static int test_running = 0;
3050 static float test_time = 0.0f;
3052 static int snds[NUM_MIXED_SOUNDS];
3055 if ( test_running ) {
3057 test_time += flFrametime;
3058 if ( framecount >= NUM_FRAMES_TEST ) {
3060 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3061 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3066 if ( Test_begin == 1 ) {
3072 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3075 // start looping digital sounds
3076 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3077 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3084 DCF(dcf_fov, "Change the field of view")
3087 dc_get_arg(ARG_FLOAT|ARG_NONE);
3088 if ( Dc_arg_type & ARG_NONE ) {
3089 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3090 dc_printf( "Zoom factor reset\n" );
3092 if ( Dc_arg_type & ARG_FLOAT ) {
3093 if (Dc_arg_float < 0.25f) {
3094 Viewer_zoom = 0.25f;
3095 dc_printf("Zoom factor pinned at 0.25.\n");
3096 } else if (Dc_arg_float > 1.25f) {
3097 Viewer_zoom = 1.25f;
3098 dc_printf("Zoom factor pinned at 1.25.\n");
3100 Viewer_zoom = Dc_arg_float;
3106 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3109 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3113 DCF(framerate_cap, "Sets the framerate cap")
3116 dc_get_arg(ARG_INT);
3117 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3118 Framerate_cap = Dc_arg_int;
3120 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3126 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3127 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3128 dc_printf("[n] must be from 1 to 120.\n");
3132 if ( Framerate_cap )
3133 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3135 dc_printf("There is no framerate cap currently active.\n");
3139 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3140 int Show_viewing_from_self = 0;
3142 void say_view_target()
3144 object *view_target;
3146 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3147 view_target = &Objects[Player_ai->target_objnum];
3149 view_target = Player_obj;
3151 if (Game_mode & GM_DEAD) {
3152 if (Player_ai->target_objnum != -1)
3153 view_target = &Objects[Player_ai->target_objnum];
3156 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3157 if (view_target != Player_obj){
3159 char *view_target_name = NULL;
3160 switch(Objects[Player_ai->target_objnum].type) {
3162 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3165 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3166 Viewer_mode &= ~VM_OTHER_SHIP;
3168 case OBJ_JUMP_NODE: {
3169 char jump_node_name[128];
3170 strcpy(jump_node_name, XSTR( "jump node", 184));
3171 view_target_name = jump_node_name;
3172 Viewer_mode &= ~VM_OTHER_SHIP;
3181 if ( view_target_name ) {
3182 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3183 Show_viewing_from_self = 1;
3186 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3187 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3188 Show_viewing_from_self = 1;
3190 if (Show_viewing_from_self)
3191 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3196 Last_view_target = view_target;
3200 float Game_hit_x = 0.0f;
3201 float Game_hit_y = 0.0f;
3203 // Reset at the beginning of each frame
3204 void game_whack_reset()
3210 // Apply a 2d whack to the player
3211 void game_whack_apply( float x, float y )
3213 // Do some force feedback
3214 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3220 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3223 // call to apply a "shudder"
3224 void game_shudder_apply(int time, float intensity)
3226 Game_shudder_time = timestamp(time);
3227 Game_shudder_total = time;
3228 Game_shudder_intensity = intensity;
3231 #define FF_SCALE 10000
3232 void apply_hud_shake(matrix *eye_orient)
3234 if (Viewer_obj == Player_obj) {
3235 physics_info *pi = &Player_obj->phys_info;
3243 // Make eye shake due to afterburner
3244 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3247 dtime = timestamp_until(pi->afterburner_decay);
3251 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3252 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3255 // Make eye shake due to engine wash
3257 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3260 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3261 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3263 // get the intensity
3264 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3268 vm_vec_rand_vec_quick(&rand_vec);
3271 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3275 // make hud shake due to shuddering
3276 if(Game_shudder_time != -1){
3277 // if the timestamp has elapsed
3278 if(timestamp_elapsed(Game_shudder_time)){
3279 Game_shudder_time = -1;
3281 // otherwise apply some shudder
3285 dtime = timestamp_until(Game_shudder_time);
3289 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));
3290 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));
3295 vm_angles_2_matrix(&tm, &tangles);
3296 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3297 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3298 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3299 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3304 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3306 // Player's velocity just before he blew up. Used to keep camera target moving.
3307 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3309 // Set eye_pos and eye_orient based on view mode.
3310 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3314 static int last_Viewer_mode = 0;
3315 static int last_Game_mode = 0;
3316 static int last_Viewer_objnum = -1;
3318 // This code is supposed to detect camera "cuts"... like going between
3321 // determine if we need to regenerate the nebula
3322 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3323 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3324 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3325 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3326 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3327 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3328 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3329 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3330 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3333 // regenerate the nebula
3337 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3338 //mprintf(( "************** Camera cut! ************\n" ));
3339 last_Viewer_mode = Viewer_mode;
3340 last_Game_mode = Game_mode;
3342 // Camera moved. Tell stars & debris to not do blurring.
3348 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3349 player_display_packlock_view();
3352 game_set_view_clip();
3354 if (Game_mode & GM_DEAD) {
3355 vector vec_to_deader, view_pos;
3358 Viewer_mode |= VM_DEAD_VIEW;
3360 if (Player_ai->target_objnum != -1) {
3361 int view_from_player = 1;
3363 if (Viewer_mode & VM_OTHER_SHIP) {
3364 // View from target.
3365 Viewer_obj = &Objects[Player_ai->target_objnum];
3367 last_Viewer_objnum = Player_ai->target_objnum;
3369 if ( Viewer_obj->type == OBJ_SHIP ) {
3370 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3371 view_from_player = 0;
3374 last_Viewer_objnum = -1;
3377 if ( view_from_player ) {
3378 // View target from player ship.
3380 *eye_pos = Player_obj->pos;
3381 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3382 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3385 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3387 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3388 dist += flFrametime * 16.0f;
3390 vm_vec_scale(&vec_to_deader, -dist);
3391 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3393 view_pos = Player_obj->pos;
3395 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3396 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3397 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3398 Dead_player_last_vel = Player_obj->phys_info.vel;
3399 //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));
3400 } else if (Player_ai->target_objnum != -1) {
3401 view_pos = Objects[Player_ai->target_objnum].pos;
3403 // Make camera follow explosion, but gradually slow down.
3404 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3405 view_pos = Player_obj->pos;
3406 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3407 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3410 *eye_pos = Dead_camera_pos;
3412 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3414 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3419 // if supernova shockwave
3420 if(supernova_camera_cut()){
3424 // call it dead view
3425 Viewer_mode |= VM_DEAD_VIEW;
3427 // set eye pos and orient
3428 supernova_set_view(eye_pos, eye_orient);
3430 // If already blown up, these other modes can override.
3431 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3432 Viewer_mode &= ~VM_DEAD_VIEW;
3434 Viewer_obj = Player_obj;
3436 if (Viewer_mode & VM_OTHER_SHIP) {
3437 if (Player_ai->target_objnum != -1){
3438 Viewer_obj = &Objects[Player_ai->target_objnum];
3439 last_Viewer_objnum = Player_ai->target_objnum;
3441 Viewer_mode &= ~VM_OTHER_SHIP;
3442 last_Viewer_objnum = -1;
3445 last_Viewer_objnum = -1;
3448 if (Viewer_mode & VM_EXTERNAL) {
3451 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3452 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3454 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3456 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3457 vm_vec_normalize(&eye_dir);
3458 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3461 // Modify the orientation based on head orientation.
3462 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3464 } else if ( Viewer_mode & VM_CHASE ) {
3467 if ( Viewer_obj->phys_info.speed < 0.1 )
3468 move_dir = Viewer_obj->orient.fvec;
3470 move_dir = Viewer_obj->phys_info.vel;
3471 vm_vec_normalize(&move_dir);
3474 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3475 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3476 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3477 vm_vec_normalize(&eye_dir);
3479 // JAS: I added the following code because if you slew up using
3480 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3481 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3482 // call because the up and the forward vector are the same. I fixed
3483 // it by adding in a fraction of the right vector all the time to the
3485 vector tmp_up = Viewer_obj->orient.uvec;
3486 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3488 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3491 // Modify the orientation based on head orientation.
3492 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3493 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3494 *eye_pos = Camera_pos;
3496 ship * shipp = &Ships[Player_obj->instance];
3498 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3499 vm_vec_normalize(&eye_dir);
3500 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3503 // get an eye position based upon the correct type of object
3504 switch(Viewer_obj->type){
3506 // make a call to get the eye point for the player object
3507 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3510 // make a call to get the eye point for the player object
3511 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3517 #ifdef JOHNS_DEBUG_CODE
3518 john_debug_stuff(&eye_pos, &eye_orient);
3524 apply_hud_shake(eye_orient);
3526 // setup neb2 rendering
3527 neb2_render_setup(eye_pos, eye_orient);
3531 extern void ai_debug_render_stuff();
3534 int Game_subspace_effect = 0;
3535 DCF_BOOL( subspace, Game_subspace_effect );
3537 // Does everything needed to render a frame
3538 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3542 g3_start_frame(game_zbuffer);
3543 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3545 // maybe offset the HUD (jitter stuff)
3546 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3547 HUD_set_offsets(Viewer_obj, !dont_offset);
3549 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3550 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3551 // must be done before ships are rendered
3552 if ( MULTIPLAYER_CLIENT ) {
3553 shield_point_multi_setup();
3556 if ( Game_subspace_effect ) {
3557 stars_draw(0,0,0,1);
3559 stars_draw(1,1,1,0);
3562 obj_render_all(obj_render);
3563 beam_render_all(); // render all beam weapons
3564 particle_render_all(); // render particles after everything else.
3565 trail_render_all(); // render missilie trails after everything else.
3566 mflash_render_all(); // render all muzzle flashes
3568 // Why do we not show the shield effect in these modes? Seems ok.
3569 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3573 // render nebula lightning
3576 // render local player nebula
3577 neb2_render_player();
3580 ai_debug_render_stuff();
3583 #ifndef RELEASE_REAL
3584 // game_framerate_check();
3588 extern void snd_spew_debug_info();
3589 snd_spew_debug_info();
3592 //================ END OF 3D RENDERING STUFF ====================
3596 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3597 hud_maybe_clear_head_area();
3598 anim_render_all(0, flFrametime);
3601 extern int Multi_display_netinfo;
3602 if(Multi_display_netinfo){
3603 extern void multi_display_netinfo();
3604 multi_display_netinfo();
3607 game_tst_frame_pre();
3610 do_timing_test(flFrametime);
3614 extern int OO_update_index;
3615 multi_rate_display(OO_update_index, 375, 0);
3620 extern void oo_display();
3627 //#define JOHNS_DEBUG_CODE 1
3629 #ifdef JOHNS_DEBUG_CODE
3630 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3632 //if ( keyd_pressed[KEY_LSHIFT] )
3634 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3636 model_subsystem *turret = tsys->system_info;
3638 if (turret->type == SUBSYSTEM_TURRET ) {
3640 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3642 ship_model_start(tobj);
3644 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3645 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3646 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3648 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3650 ship_model_stop(tobj);
3660 // following function for dumping frames for purposes of building trailers.
3663 // function to toggle state of dumping every frame into PCX when playing the game
3664 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3668 if ( Debug_dump_frames == 0 ) {
3670 Debug_dump_frames = 15;
3671 Debug_dump_trigger = 0;
3672 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3673 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3676 Debug_dump_frames = 0;
3677 Debug_dump_trigger = 0;
3678 gr_dump_frame_stop();
3679 dc_printf( "Frame dumping is now OFF\n" );
3685 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3689 if ( Debug_dump_frames == 0 ) {
3691 Debug_dump_frames = 15;
3692 Debug_dump_trigger = 1;
3693 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3694 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3697 Debug_dump_frames = 0;
3698 Debug_dump_trigger = 0;
3699 gr_dump_frame_stop();
3700 dc_printf( "Frame dumping is now OFF\n" );
3706 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3710 if ( Debug_dump_frames == 0 ) {
3712 Debug_dump_frames = 30;
3713 Debug_dump_trigger = 0;
3714 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3715 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3718 Debug_dump_frames = 0;
3719 Debug_dump_trigger = 0;
3720 gr_dump_frame_stop();
3721 dc_printf( "Frame dumping is now OFF\n" );
3727 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3731 if ( Debug_dump_frames == 0 ) {
3733 Debug_dump_frames = 30;
3734 Debug_dump_trigger = 1;
3735 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3736 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3739 Debug_dump_frames = 0;
3740 Debug_dump_trigger = 0;
3741 gr_dump_frame_stop();
3742 dc_printf( "Triggered frame dumping is now OFF\n" );
3748 void game_maybe_dump_frame()
3750 if ( !Debug_dump_frames ){
3754 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3761 Debug_dump_frame_num++;
3767 extern int Player_dead_state;
3769 // Flip the page and time how long it took.
3770 void game_flip_page_and_time_it()
3774 t1 = timer_get_fixed_seconds();
3776 t2 = timer_get_fixed_seconds();
3778 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3779 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3782 void game_simulation_frame()
3784 // blow ships up in multiplayer dogfight
3785 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){
3786 // blow up all non-player ships
3787 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3790 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3792 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)){
3793 moveup = GET_NEXT(moveup);
3796 shipp = &Ships[Objects[moveup->objnum].instance];
3797 sip = &Ship_info[shipp->ship_info_index];
3799 // only blow up small ships
3800 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3801 // function to simply explode a ship where it is currently at
3802 ship_self_destruct( &Objects[moveup->objnum] );
3805 moveup = GET_NEXT(moveup);
3811 // process AWACS stuff - do this first thing
3814 // single player, set Player hits_this_frame to 0
3815 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3816 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3817 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3821 supernova_process();
3822 if(supernova_active() >= 5){
3826 // fire targeting lasers now so that
3827 // 1 - created this frame
3828 // 2 - collide this frame
3829 // 3 - render this frame
3830 // 4 - ignored and deleted next frame
3831 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3833 ship_process_targeting_lasers();
3835 // do this here so that it works for multiplayer
3837 // get viewer direction
3838 int viewer_direction = PHYSICS_VIEWER_REAR;
3840 if(Viewer_mode == 0){
3841 viewer_direction = PHYSICS_VIEWER_FRONT;
3843 if(Viewer_mode & VM_PADLOCK_UP){
3844 viewer_direction = PHYSICS_VIEWER_UP;
3846 else if(Viewer_mode & VM_PADLOCK_REAR){
3847 viewer_direction = PHYSICS_VIEWER_REAR;
3849 else if(Viewer_mode & VM_PADLOCK_LEFT){
3850 viewer_direction = PHYSICS_VIEWER_LEFT;
3852 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3853 viewer_direction = PHYSICS_VIEWER_RIGHT;
3856 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3858 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3861 #define VM_PADLOCK_UP (1 << 7)
3862 #define VM_PADLOCK_REAR (1 << 8)
3863 #define VM_PADLOCK_LEFT (1 << 9)
3864 #define VM_PADLOCK_RIGHT (1 << 10)
3866 // evaluate mission departures and arrivals before we process all objects.
3867 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3869 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3870 // ships/wing packets.
3871 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3872 mission_parse_eval_stuff();
3875 // if we're an observer, move ourselves seperately from the standard physics
3876 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3877 obj_observer_move(flFrametime);
3880 // move all the objects now
3881 obj_move_all(flFrametime);
3883 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3884 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3885 // ship_check_cargo_all();
3886 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3887 mission_eval_goals();
3891 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3892 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3893 training_check_objectives();
3896 // do all interpolation now
3897 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3898 // client side processing of warping in effect stages
3899 multi_do_client_warp(flFrametime);
3901 // client side movement of an observer
3902 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3903 obj_observer_move(flFrametime);
3906 // move all objects - does interpolation now as well
3907 obj_move_all(flFrametime);
3910 // only process the message queue when the player is "in" the game
3911 if ( !Pre_player_entry ){
3912 message_queue_process(); // process any messages send to the player
3915 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3916 message_maybe_distort(); // maybe distort incoming message if comms damaged
3917 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3918 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3919 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3922 if(!(Game_mode & GM_STANDALONE_SERVER)){
3923 // process some stuff every frame (before frame is rendered)
3924 emp_process_local();
3926 hud_update_frame(); // update hud systems
3928 if (!physics_paused) {
3929 // Move particle system
3930 particle_move_all(flFrametime);
3932 // Move missile trails
3933 trail_move_all(flFrametime);
3935 // process muzzle flashes
3936 mflash_process_all();
3938 // Flash the gun flashes
3939 shipfx_flash_do_frame(flFrametime);
3941 shockwave_move_all(flFrametime); // update all the shockwaves
3944 // subspace missile strikes
3947 obj_snd_do_frame(); // update the object-linked persistant sounds
3948 game_maybe_update_sound_environment();
3949 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3951 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3953 if ( Game_subspace_effect ) {
3954 game_start_subspace_ambient_sound();
3960 // Maybe render and process the dead-popup
3961 void game_maybe_do_dead_popup(float frametime)
3963 if ( popupdead_is_active() ) {
3965 int choice = popupdead_do_frame(frametime);
3967 if ( Game_mode & GM_NORMAL ) {
3971 if(game_do_cd_mission_check(Game_current_mission_filename)){
3972 gameseq_post_event(GS_EVENT_ENTER_GAME);
3974 gameseq_post_event(GS_EVENT_MAIN_MENU);
3979 gameseq_post_event(GS_EVENT_END_GAME);
3984 if(game_do_cd_mission_check(Game_current_mission_filename)){
3985 gameseq_post_event(GS_EVENT_START_GAME);
3987 gameseq_post_event(GS_EVENT_MAIN_MENU);
3991 // this should only happen during a red alert mission
3994 Assert(The_mission.red_alert);
3995 if(!The_mission.red_alert){
3997 if(game_do_cd_mission_check(Game_current_mission_filename)){
3998 gameseq_post_event(GS_EVENT_START_GAME);
4000 gameseq_post_event(GS_EVENT_MAIN_MENU);
4005 // choose the previous mission
4006 mission_campaign_previous_mission();
4008 if(game_do_cd_mission_check(Game_current_mission_filename)){
4009 gameseq_post_event(GS_EVENT_START_GAME);
4011 gameseq_post_event(GS_EVENT_MAIN_MENU);
4022 case POPUPDEAD_DO_MAIN_HALL:
4023 multi_quit_game(PROMPT_NONE,-1);
4026 case POPUPDEAD_DO_RESPAWN:
4027 multi_respawn_normal();
4028 event_music_player_respawn();
4031 case POPUPDEAD_DO_OBSERVER:
4032 multi_respawn_observer();
4033 event_music_player_respawn_as_observer();
4042 if ( leave_popup ) {
4048 // returns true if player is actually in a game_play stats
4049 int game_actually_playing()
4053 state = gameseq_get_state();
4054 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4060 // Draw the 2D HUD gauges
4061 void game_render_hud_2d()
4063 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4067 HUD_render_2d(flFrametime);
4071 // Draw the 3D-dependant HUD gauges
4072 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4074 g3_start_frame(0); // 0 = turn zbuffering off
4075 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4077 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4078 HUD_render_3d(flFrametime);
4082 game_sunspot_process(flFrametime);
4084 // Diminish the palette effect
4085 game_flash_diminish(flFrametime);
4093 int actually_playing;
4094 fix total_time1, total_time2;
4095 fix render2_time1=0, render2_time2=0;
4096 fix render3_time1=0, render3_time2=0;
4097 fix flip_time1=0, flip_time2=0;
4098 fix clear_time1=0, clear_time2=0;
4104 if (Framerate_delay) {
4105 int start_time = timer_get_milliseconds();
4106 while (timer_get_milliseconds() < start_time + Framerate_delay)
4112 demo_do_frame_start();
4114 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4119 // start timing frame
4120 timing_frame_start();
4122 total_time1 = timer_get_fixed_seconds();
4124 // var to hold which state we are in
4125 actually_playing = game_actually_playing();
4127 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4128 if (!(Game_mode & GM_STANDALONE_SERVER)){
4129 Assert( OBJ_INDEX(Player_obj) >= 0 );
4133 if (Missiontime > Entry_delay_time){
4134 Pre_player_entry = 0;
4136 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4139 // Note: These are done even before the player enters, else buffers can overflow.
4140 if (! (Game_mode & GM_STANDALONE_SERVER)){
4144 shield_frame_init();
4146 if ( Player->control_mode != PCM_NORMAL )
4149 if ( !Pre_player_entry && actually_playing ) {
4150 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4152 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4153 game_process_keys();
4155 // don't read flying controls if we're playing a demo back
4156 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4157 read_player_controls( Player_obj, flFrametime);
4161 // if we're not the master, we may have to send the server-critical ship status button_info bits
4162 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4163 multi_maybe_send_ship_status();
4168 // Reset the whack stuff
4171 // These two lines must be outside of Pre_player_entry code,
4172 // otherwise too many lights are added.
4175 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4179 game_simulation_frame();
4181 // if not actually in a game play state, then return. This condition could only be true in
4182 // a multiplayer game.
4183 if ( !actually_playing ) {
4184 Assert( Game_mode & GM_MULTIPLAYER );
4188 if (!Pre_player_entry) {
4189 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4190 clear_time1 = timer_get_fixed_seconds();
4191 // clear the screen to black
4193 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4197 clear_time2 = timer_get_fixed_seconds();
4198 render3_time1 = timer_get_fixed_seconds();
4199 game_render_frame_setup(&eye_pos, &eye_orient);
4200 game_render_frame( &eye_pos, &eye_orient );
4202 // save the eye position and orientation
4203 if ( Game_mode & GM_MULTIPLAYER ) {
4204 Net_player->s_info.eye_pos = eye_pos;
4205 Net_player->s_info.eye_orient = eye_orient;
4208 hud_show_target_model();
4210 // check to see if we should display the death died popup
4211 if(Game_mode & GM_DEAD_BLEW_UP){
4212 if(Game_mode & GM_MULTIPLAYER){
4213 // catch the situation where we're supposed to be warping out on this transition
4214 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4215 gameseq_post_event(GS_EVENT_DEBRIEF);
4216 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4217 Player_died_popup_wait = -1;
4221 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4222 Player_died_popup_wait = -1;
4228 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4229 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4230 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4231 if(!popupdead_is_active()){
4235 Player_multi_died_check = -1;
4239 render3_time2 = timer_get_fixed_seconds();
4240 render2_time1 = timer_get_fixed_seconds();
4243 game_get_framerate();
4244 game_show_framerate();
4246 game_show_time_left();
4248 // Draw the 2D HUD gauges
4249 if(supernova_active() < 3){
4250 game_render_hud_2d();
4253 game_set_view_clip();
4255 // Draw 3D HUD gauges
4256 game_render_hud_3d(&eye_pos, &eye_orient);
4260 render2_time2 = timer_get_fixed_seconds();
4262 // maybe render and process the dead popup
4263 game_maybe_do_dead_popup(flFrametime);
4265 // start timing frame
4266 timing_frame_stop();
4267 // timing_display(30, 10);
4269 // If a regular popup is active, don't flip (popup code flips)
4270 if( !popup_running_state() ){
4271 flip_time1 = timer_get_fixed_seconds();
4272 game_flip_page_and_time_it();
4273 flip_time2 = timer_get_fixed_seconds();
4277 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4280 game_show_standalone_framerate();
4284 game_do_training_checks();
4287 // process lightning (nebula only)
4290 total_time2 = timer_get_fixed_seconds();
4292 // Got some timing numbers
4293 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4294 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4295 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4296 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4297 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4300 demo_do_frame_end();
4302 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4308 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4309 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4310 // died. This resulted in screwed up death sequences.
4312 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4313 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4314 static int timer_paused=0;
4315 static int stop_count,start_count;
4316 static int time_stopped,time_started;
4317 int saved_timestamp_ticker = -1;
4319 void game_reset_time()
4321 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4325 // Last_time = timer_get_fixed_seconds();
4331 void game_stop_time()
4333 if (timer_paused==0) {
4335 time = timer_get_fixed_seconds();
4336 // Save how much time progressed so far in the frame so we can
4337 // use it when we unpause.
4338 Last_delta_time = time - Last_time;
4340 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4341 if (Last_delta_time < 0) {
4342 #if defined(TIMER_TEST) && !defined(NDEBUG)
4343 Int3(); //get Matt!!!!
4345 Last_delta_time = 0;
4347 #if defined(TIMER_TEST) && !defined(NDEBUG)
4348 time_stopped = time;
4351 // Stop the timer_tick stuff...
4352 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4353 saved_timestamp_ticker = timestamp_ticker;
4357 #if defined(TIMER_TEST) && !defined(NDEBUG)
4362 void game_start_time()
4365 Assert(timer_paused >= 0);
4366 if (timer_paused==0) {
4368 time = timer_get_fixed_seconds();
4369 #if defined(TIMER_TEST) && !defined(NDEBUG)
4371 Int3(); //get Matt!!!!
4374 // Take current time, and set it backwards to account for time
4375 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4376 // will be correct when it goes to calculate the frametime next
4378 Last_time = time - Last_delta_time;
4379 #if defined(TIMER_TEST) && !defined(NDEBUG)
4380 time_started = time;
4383 // Restore the timer_tick stuff...
4384 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4385 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4386 timestamp_ticker = saved_timestamp_ticker;
4387 saved_timestamp_ticker = -1;
4390 #if defined(TIMER_TEST) && !defined(NDEBUG)
4396 void game_set_frametime(int state)
4399 float frame_cap_diff;
4401 thistime = timer_get_fixed_seconds();
4403 if ( Last_time == 0 )
4404 Frametime = F1_0 / 30;
4406 Frametime = thistime - Last_time;
4408 // Frametime = F1_0 / 30;
4410 fix debug_frametime = Frametime; // Just used to display frametime.
4412 // If player hasn't entered mission yet, make frame take 1/4 second.
4413 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4416 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4418 fix frame_speed = F1_0 / Debug_dump_frames;
4420 if (Frametime > frame_speed ){
4421 nprintf(("warning","slow frame: %x\n",Frametime));
4424 thistime = timer_get_fixed_seconds();
4425 Frametime = thistime - Last_time;
4426 } while (Frametime < frame_speed );
4428 Frametime = frame_speed;
4432 Assert( Framerate_cap > 0 );
4434 // Cap the framerate so it doesn't get too high.
4438 cap = F1_0/Framerate_cap;
4439 if (Frametime < cap) {
4440 thistime = cap - Frametime;
4441 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4442 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4444 thistime = timer_get_fixed_seconds();
4448 if((Game_mode & GM_STANDALONE_SERVER) &&
4449 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4451 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4452 Sleep((DWORD)(frame_cap_diff*1000));
4454 thistime += fl2f((frame_cap_diff));
4456 Frametime = thistime - Last_time;
4459 // If framerate is too low, cap it.
4460 if (Frametime > MAX_FRAMETIME) {
4462 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4464 // to remove warnings in release build
4465 debug_frametime = fl2f(flFrametime);
4467 Frametime = MAX_FRAMETIME;
4470 Frametime = fixmul(Frametime, Game_time_compression);
4472 Last_time = thistime;
4473 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4475 flFrametime = f2fl(Frametime);
4476 //if(!(Game_mode & GM_PLAYING_DEMO)){
4477 timestamp_inc(flFrametime);
4479 /* if ((Framecount > 0) && (Framecount < 10)) {
4480 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4485 // This is called from game_do_frame(), and from navmap_do_frame()
4486 void game_update_missiontime()
4488 // TODO JAS: Put in if and move this into game_set_frametime,
4489 // fix navmap to call game_stop/start_time
4490 //if ( !timer_paused )
4491 Missiontime += Frametime;
4494 void game_do_frame()
4496 game_set_frametime(GS_STATE_GAME_PLAY);
4497 game_update_missiontime();
4499 if (Game_mode & GM_STANDALONE_SERVER) {
4500 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4503 if ( game_single_step && (last_single_step == game_single_step) ) {
4504 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4505 while( key_checkch() == 0 )
4507 os_set_title( XSTR( "FreeSpace", 171) );
4508 Last_time = timer_get_fixed_seconds();
4511 last_single_step = game_single_step;
4513 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4514 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4518 Keep_mouse_centered = 0;
4519 monitor_update(); // Update monitor variables
4522 void multi_maybe_do_frame()
4524 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4529 int Joymouse_button_status = 0;
4531 // Flush all input devices
4539 Joymouse_button_status = 0;
4541 //mprintf(("Game flush!\n" ));
4544 // function for multiplayer only which calls game_do_state_common() when running the
4546 void game_do_dc_networking()
4548 Assert( Game_mode & GM_MULTIPLAYER );
4550 game_do_state_common( gameseq_get_state() );
4553 // Call this whenever in a loop, or when you need to check for a keystroke.
4554 int game_check_key()
4560 // convert keypad enter to normal enter
4561 if ((k & KEY_MASK) == KEY_PADENTER)
4562 k = (k & ~KEY_MASK) | KEY_ENTER;
4569 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4570 static int Demo_show_trailer_timestamp = 0;
4572 void demo_reset_trailer_timer()
4574 Demo_show_trailer_timestamp = timer_get_milliseconds();
4577 void demo_maybe_show_trailer(int k)
4580 // if key pressed, reset demo trailer timer
4582 demo_reset_trailer_timer();
4586 // if mouse moved, reset demo trailer timer
4589 mouse_get_delta(&dx, &dy);
4590 if ( (dx > 0) || (dy > 0) ) {
4591 demo_reset_trailer_timer();
4595 // if joystick has moved, reset demo trailer timer
4598 joy_get_delta(&dx, &dy);
4599 if ( (dx > 0) || (dy > 0) ) {
4600 demo_reset_trailer_timer();
4604 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4605 // the low-level code. Ugly, I know... but was the simplest and most
4608 // if 30 seconds since last demo trailer time reset, launch movie
4609 if ( os_foreground() ) {
4610 int now = timer_get_milliseconds();
4611 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4612 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4614 movie_play( NOX("fstrailer2.mve") );
4615 demo_reset_trailer_timer();
4623 // same as game_check_key(), except this is used while actually in the game. Since there
4624 // generally are differences between game control keys and general UI keys, makes sense to
4625 // have seperate functions for each case. If you are not checking a game control while in a
4626 // mission, you should probably be using game_check_key() instead.
4631 if (!os_foreground()) {
4636 // If we're in a single player game, pause it.
4637 if (!(Game_mode & GM_MULTIPLAYER)){
4638 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4639 game_process_pause_key();
4647 demo_maybe_show_trailer(k);
4650 // Move the mouse cursor with the joystick.
4651 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4652 // Move the mouse cursor with the joystick
4656 joy_get_pos( &jx, &jy, &jz, &jr );
4658 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4659 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4662 mouse_get_real_pos( &mx, &my );
4663 mouse_set_pos( mx+dx, my+dy );
4668 m = mouse_down(MOUSE_LEFT_BUTTON);
4670 if ( j != Joymouse_button_status ) {
4671 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4672 Joymouse_button_status = j;
4674 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4675 } else if ( (!j) && (m) ) {
4676 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4681 // if we should be ignoring keys because of some multiplayer situations
4682 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4686 // If a popup is running, don't process all the Fn keys
4687 if( popup_active() ) {
4691 state = gameseq_get_state();
4693 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4696 case KEY_DEBUGGED + KEY_BACKSP:
4701 launch_context_help();
4706 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4708 // don't allow f2 while warping out in multiplayer
4709 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4714 case GS_STATE_INITIAL_PLAYER_SELECT:
4715 case GS_STATE_OPTIONS_MENU:
4716 case GS_STATE_HUD_CONFIG:
4717 case GS_STATE_CONTROL_CONFIG:
4718 case GS_STATE_DEATH_DIED:
4719 case GS_STATE_DEATH_BLEW_UP:
4720 case GS_STATE_VIEW_MEDALS:
4724 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4731 // hotkey selection screen -- only valid from briefing and beyond.
4734 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) ) {
4735 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4741 case KEY_DEBUGGED + KEY_F3:
4742 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4745 case KEY_DEBUGGED + KEY_F4:
4746 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4750 if(Game_mode & GM_MULTIPLAYER){
4751 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4752 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4756 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4757 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4763 case KEY_ESC | KEY_SHIFTED:
4764 // make sure to quit properly out of multiplayer
4765 if(Game_mode & GM_MULTIPLAYER){
4766 multi_quit_game(PROMPT_NONE);
4769 gameseq_post_event( GS_EVENT_QUIT_GAME );
4774 case KEY_DEBUGGED + KEY_P:
4777 case KEY_PRINT_SCRN:
4779 static int counter = 0;
4784 sprintf( tmp_name, NOX("screen%02d"), counter );
4786 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4787 gr_print_screen(tmp_name);
4795 case KEY_SHIFTED | KEY_ENTER: {
4797 #if !defined(NDEBUG)
4799 if ( Game_mode & GM_NORMAL ){
4803 // if we're in multiplayer mode, do some special networking
4804 if(Game_mode & GM_MULTIPLAYER){
4805 debug_console(game_do_dc_networking);
4812 if ( Game_mode & GM_NORMAL )
4826 gameseq_post_event(GS_EVENT_QUIT_GAME);
4829 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4832 void camera_set_position( vector *pos )
4837 void camera_set_orient( matrix *orient )
4839 Camera_orient = *orient;
4842 void camera_set_velocity( vector *vel, int instantaneous )
4844 Camera_desired_velocity.x = 0.0f;
4845 Camera_desired_velocity.y = 0.0f;
4846 Camera_desired_velocity.z = 0.0f;
4848 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4849 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4850 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4852 if ( instantaneous ) {
4853 Camera_velocity = Camera_desired_velocity;
4861 vector new_vel, delta_pos;
4863 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4864 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4865 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4867 Camera_velocity = new_vel;
4869 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4871 vm_vec_add2( &Camera_pos, &delta_pos );
4873 float ot = Camera_time+0.0f;
4875 Camera_time += flFrametime;
4877 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4880 tmp.z = 4.739f; // always go this fast forward.
4882 // pick x and y velocities so they are always on a
4883 // circle with a 25 m radius.
4885 float tmp_angle = frand()*PI2;
4887 tmp.x = 22.0f * (float)sin(tmp_angle);
4888 tmp.y = -22.0f * (float)cos(tmp_angle);
4890 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4892 //mprintf(( "Changing velocity!\n" ));
4893 camera_set_velocity( &tmp, 0 );
4896 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4897 vector tmp = { 0.0f, 0.0f, 0.0f };
4898 camera_set_velocity( &tmp, 0 );
4903 void end_demo_campaign_do()
4905 #if defined(FS2_DEMO)
4906 // show upsell screens
4907 demo_upsell_show_screens();
4908 #elif defined(OEM_BUILD)
4909 // show oem upsell screens
4910 oem_upsell_show_screens();
4913 // drop into main hall
4914 gameseq_post_event( GS_EVENT_MAIN_MENU );
4917 // All code to process events. This is the only place
4918 // that you should change the state of the game.
4919 void game_process_event( int current_state, int event )
4921 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4924 case GS_EVENT_SIMULATOR_ROOM:
4925 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4928 case GS_EVENT_MAIN_MENU:
4929 gameseq_set_state(GS_STATE_MAIN_MENU);
4932 case GS_EVENT_OPTIONS_MENU:
4933 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4936 case GS_EVENT_BARRACKS_MENU:
4937 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4940 case GS_EVENT_TECH_MENU:
4941 gameseq_set_state(GS_STATE_TECH_MENU);
4944 case GS_EVENT_TRAINING_MENU:
4945 gameseq_set_state(GS_STATE_TRAINING_MENU);
4948 case GS_EVENT_START_GAME:
4949 Select_default_ship = 0;
4950 Player_multi_died_check = -1;
4951 gameseq_set_state(GS_STATE_CMD_BRIEF);
4954 case GS_EVENT_START_BRIEFING:
4955 gameseq_set_state(GS_STATE_BRIEFING);
4958 case GS_EVENT_DEBRIEF:
4959 // did we end the campaign in the main freespace 2 single player campaign?
4960 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4961 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4963 gameseq_set_state(GS_STATE_DEBRIEF);
4966 Player_multi_died_check = -1;
4969 case GS_EVENT_SHIP_SELECTION:
4970 gameseq_set_state( GS_STATE_SHIP_SELECT );
4973 case GS_EVENT_WEAPON_SELECTION:
4974 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4977 case GS_EVENT_ENTER_GAME:
4979 // maybe start recording a demo
4981 demo_start_record("test.fsd");
4985 if (Game_mode & GM_MULTIPLAYER) {
4986 // if we're respawning, make sure we change the view mode so that the hud shows up
4987 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4991 gameseq_set_state(GS_STATE_GAME_PLAY);
4993 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4996 Player_multi_died_check = -1;
4998 // clear multiplayer button info
4999 extern button_info Multi_ship_status_bi;
5000 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5002 Start_time = f2fl(timer_get_approx_seconds());
5004 mprintf(("Entering game at time = %7.3f\n", Start_time));
5008 case GS_EVENT_START_GAME_QUICK:
5009 Select_default_ship = 1;
5010 gameseq_post_event(GS_EVENT_ENTER_GAME);
5014 case GS_EVENT_END_GAME:
5015 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5016 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5017 gameseq_set_state(GS_STATE_MAIN_MENU);
5022 Player_multi_died_check = -1;
5025 case GS_EVENT_QUIT_GAME:
5026 main_hall_stop_music();
5027 main_hall_stop_ambient();
5028 gameseq_set_state(GS_STATE_QUIT_GAME);
5030 Player_multi_died_check = -1;
5033 case GS_EVENT_GAMEPLAY_HELP:
5034 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5037 case GS_EVENT_PAUSE_GAME:
5038 gameseq_push_state(GS_STATE_GAME_PAUSED);
5041 case GS_EVENT_DEBUG_PAUSE_GAME:
5042 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5045 case GS_EVENT_TRAINING_PAUSE:
5046 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5049 case GS_EVENT_PREVIOUS_STATE:
5050 gameseq_pop_state();
5053 case GS_EVENT_TOGGLE_FULLSCREEN:
5054 #ifndef HARDWARE_ONLY
5056 if ( gr_screen.mode == GR_SOFTWARE ) {
5057 gr_init( GR_640, GR_DIRECTDRAW );
5058 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5059 gr_init( GR_640, GR_SOFTWARE );
5065 case GS_EVENT_TOGGLE_GLIDE:
5067 if ( gr_screen.mode != GR_GLIDE ) {
5068 gr_init( GR_640, GR_GLIDE );
5070 gr_init( GR_640, GR_SOFTWARE );
5075 case GS_EVENT_LOAD_MISSION_MENU:
5076 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5079 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5080 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5083 case GS_EVENT_HUD_CONFIG:
5084 gameseq_push_state( GS_STATE_HUD_CONFIG );
5087 case GS_EVENT_CONTROL_CONFIG:
5088 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5091 case GS_EVENT_DEATH_DIED:
5092 gameseq_set_state( GS_STATE_DEATH_DIED );
5095 case GS_EVENT_DEATH_BLEW_UP:
5096 if ( current_state == GS_STATE_DEATH_DIED ) {
5097 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5098 event_music_player_death();
5100 // multiplayer clients set their extra check here
5101 if(Game_mode & GM_MULTIPLAYER){
5102 // set the multi died absolute last chance check
5103 Player_multi_died_check = time(NULL);
5106 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5110 case GS_EVENT_NEW_CAMPAIGN:
5111 if (!mission_load_up_campaign()){
5112 readyroom_continue_campaign();
5115 Player_multi_died_check = -1;
5118 case GS_EVENT_CAMPAIGN_CHEAT:
5119 if (!mission_load_up_campaign()){
5121 // bash campaign value
5122 extern char Main_hall_campaign_cheat[512];
5125 // look for the mission
5126 for(idx=0; idx<Campaign.num_missions; idx++){
5127 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5128 Campaign.next_mission = idx;
5129 Campaign.prev_mission = idx - 1;
5136 readyroom_continue_campaign();
5139 Player_multi_died_check = -1;
5142 case GS_EVENT_CAMPAIGN_ROOM:
5143 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5146 case GS_EVENT_CMD_BRIEF:
5147 gameseq_set_state(GS_STATE_CMD_BRIEF);
5150 case GS_EVENT_RED_ALERT:
5151 gameseq_set_state(GS_STATE_RED_ALERT);
5154 case GS_EVENT_CREDITS:
5155 gameseq_set_state( GS_STATE_CREDITS );
5158 case GS_EVENT_VIEW_MEDALS:
5159 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5162 case GS_EVENT_SHOW_GOALS:
5163 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5166 case GS_EVENT_HOTKEY_SCREEN:
5167 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5170 // multiplayer stuff follow these comments
5172 case GS_EVENT_MULTI_JOIN_GAME:
5173 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5176 case GS_EVENT_MULTI_HOST_SETUP:
5177 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5180 case GS_EVENT_MULTI_CLIENT_SETUP:
5181 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5184 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5185 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5188 case GS_EVENT_MULTI_STD_WAIT:
5189 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5192 case GS_EVENT_STANDALONE_MAIN:
5193 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5196 case GS_EVENT_MULTI_PAUSE:
5197 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5200 case GS_EVENT_INGAME_PRE_JOIN:
5201 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5204 case GS_EVENT_EVENT_DEBUG:
5205 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5208 // Start a warpout where player automatically goes 70 no matter what
5209 // and can't cancel out of it.
5210 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5211 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5213 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5214 Player->saved_viewer_mode = Viewer_mode;
5215 Player->control_mode = PCM_WARPOUT_STAGE1;
5216 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5217 Warpout_time = 0.0f; // Start timer!
5220 case GS_EVENT_PLAYER_WARPOUT_START:
5221 if ( Player->control_mode != PCM_NORMAL ) {
5222 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5224 Player->saved_viewer_mode = Viewer_mode;
5225 Player->control_mode = PCM_WARPOUT_STAGE1;
5226 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5227 Warpout_time = 0.0f; // Start timer!
5228 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5232 case GS_EVENT_PLAYER_WARPOUT_STOP:
5233 if ( Player->control_mode != PCM_NORMAL ) {
5234 if ( !Warpout_forced ) { // cannot cancel forced warpout
5235 Player->control_mode = PCM_NORMAL;
5236 Viewer_mode = Player->saved_viewer_mode;
5237 hud_subspace_notify_abort();
5238 mprintf(( "Player put back to normal mode.\n" ));
5239 if ( Warpout_sound > -1 ) {
5240 snd_stop( Warpout_sound );
5247 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5248 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5249 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5250 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5252 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5253 shipfx_warpout_start( Player_obj );
5254 Player->control_mode = PCM_WARPOUT_STAGE2;
5255 Player->saved_viewer_mode = Viewer_mode;
5256 Viewer_mode |= VM_WARP_CHASE;
5258 vector tmp = Player_obj->pos;
5260 ship_get_eye( &tmp, &tmp_m, Player_obj );
5261 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5262 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5263 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5265 camera_set_position( &tmp );
5266 camera_set_orient( &Player_obj->orient );
5267 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5269 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5270 camera_set_velocity( &tmp_vel, 1);
5274 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5275 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5276 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5277 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5279 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5280 Player->control_mode = PCM_WARPOUT_STAGE3;
5284 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5285 mprintf(( "Player warped out. Going to debriefing!\n" ));
5286 Player->control_mode = PCM_NORMAL;
5287 Viewer_mode = Player->saved_viewer_mode;
5290 // we have a special debriefing screen for multiplayer furballs
5291 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5292 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5294 // do the normal debriefing for all other situations
5296 gameseq_post_event(GS_EVENT_DEBRIEF);
5300 case GS_EVENT_STANDALONE_POSTGAME:
5301 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5304 case GS_EVENT_INITIAL_PLAYER_SELECT:
5305 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5308 case GS_EVENT_GAME_INIT:
5309 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5310 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5312 // see if the command line option has been set to use the last pilot, and act acoordingly
5313 if( player_select_get_last_pilot() ) {
5314 // always enter the main menu -- do the automatic network startup stuff elsewhere
5315 // so that we still have valid checks for networking modes, etc.
5316 gameseq_set_state(GS_STATE_MAIN_MENU);
5318 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5323 case GS_EVENT_MULTI_MISSION_SYNC:
5324 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5327 case GS_EVENT_MULTI_START_GAME:
5328 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5331 case GS_EVENT_MULTI_HOST_OPTIONS:
5332 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5335 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5336 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5339 case GS_EVENT_TEAM_SELECT:
5340 gameseq_set_state(GS_STATE_TEAM_SELECT);
5343 case GS_EVENT_END_CAMPAIGN:
5344 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5347 case GS_EVENT_END_DEMO:
5348 gameseq_set_state(GS_STATE_END_DEMO);
5351 case GS_EVENT_LOOP_BRIEF:
5352 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5361 // Called when a state is being left.
5362 // The current state is still at old_state, but as soon as
5363 // this function leaves, then the current state will become
5364 // new state. You should never try to change the state
5365 // in here... if you think you need to, you probably really
5366 // need to post an event, not change the state.
5367 void game_leave_state( int old_state, int new_state )
5369 int end_mission = 1;
5371 switch (new_state) {
5372 case GS_STATE_GAME_PAUSED:
5373 case GS_STATE_DEBUG_PAUSED:
5374 case GS_STATE_OPTIONS_MENU:
5375 case GS_STATE_CONTROL_CONFIG:
5376 case GS_STATE_MISSION_LOG_SCROLLBACK:
5377 case GS_STATE_DEATH_DIED:
5378 case GS_STATE_SHOW_GOALS:
5379 case GS_STATE_HOTKEY_SCREEN:
5380 case GS_STATE_MULTI_PAUSED:
5381 case GS_STATE_TRAINING_PAUSED:
5382 case GS_STATE_EVENT_DEBUG:
5383 case GS_STATE_GAMEPLAY_HELP:
5384 end_mission = 0; // these events shouldn't end a mission
5388 switch (old_state) {
5389 case GS_STATE_BRIEFING:
5390 brief_stop_voices();
5391 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5392 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5393 && (new_state != GS_STATE_TEAM_SELECT) ){
5394 common_select_close();
5395 if ( new_state == GS_STATE_MAIN_MENU ) {
5396 freespace_stop_mission();
5400 // COMMAND LINE OPTION
5401 if (Cmdline_multi_stream_chat_to_file){
5402 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5403 cfclose(Multi_chat_stream);
5407 case GS_STATE_DEBRIEF:
5408 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5413 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5414 multi_df_debrief_close();
5417 case GS_STATE_LOAD_MISSION_MENU:
5418 mission_load_menu_close();
5421 case GS_STATE_SIMULATOR_ROOM:
5425 case GS_STATE_CAMPAIGN_ROOM:
5426 campaign_room_close();
5429 case GS_STATE_CMD_BRIEF:
5430 if (new_state == GS_STATE_OPTIONS_MENU) {
5435 if (new_state == GS_STATE_MAIN_MENU)
5436 freespace_stop_mission();
5441 case GS_STATE_RED_ALERT:
5445 case GS_STATE_SHIP_SELECT:
5446 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5447 new_state != GS_STATE_HOTKEY_SCREEN &&
5448 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5449 common_select_close();
5450 if ( new_state == GS_STATE_MAIN_MENU ) {
5451 freespace_stop_mission();
5456 case GS_STATE_WEAPON_SELECT:
5457 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5458 new_state != GS_STATE_HOTKEY_SCREEN &&
5459 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5460 common_select_close();
5461 if ( new_state == GS_STATE_MAIN_MENU ) {
5462 freespace_stop_mission();
5467 case GS_STATE_TEAM_SELECT:
5468 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5469 new_state != GS_STATE_HOTKEY_SCREEN &&
5470 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5471 common_select_close();
5472 if ( new_state == GS_STATE_MAIN_MENU ) {
5473 freespace_stop_mission();
5478 case GS_STATE_MAIN_MENU:
5479 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5486 case GS_STATE_OPTIONS_MENU:
5487 //game_start_time();
5488 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5489 multi_join_clear_game_list();
5491 options_menu_close();
5494 case GS_STATE_BARRACKS_MENU:
5495 if(new_state != GS_STATE_VIEW_MEDALS){
5500 case GS_STATE_MISSION_LOG_SCROLLBACK:
5501 hud_scrollback_close();
5504 case GS_STATE_TRAINING_MENU:
5505 training_menu_close();
5508 case GS_STATE_GAME_PLAY:
5509 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5510 player_save_target_and_weapon_link_prefs();
5511 game_stop_looped_sounds();
5514 sound_env_disable();
5515 joy_ff_stop_effects();
5517 // stop game time under certain conditions
5518 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5523 // shut down any recording or playing demos
5528 // when in multiplayer and going back to the main menu, send a leave game packet
5529 // right away (before calling stop mission). stop_mission was taking to long to
5530 // close mission down and I want people to get notified ASAP.
5531 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5532 multi_quit_game(PROMPT_NONE);
5535 freespace_stop_mission();
5536 Game_time_compression = F1_0;
5540 case GS_STATE_TECH_MENU:
5544 case GS_STATE_TRAINING_PAUSED:
5545 Training_num_lines = 0;
5546 // fall through to GS_STATE_GAME_PAUSED
5548 case GS_STATE_GAME_PAUSED:
5550 if ( end_mission ) {
5555 case GS_STATE_DEBUG_PAUSED:
5558 pause_debug_close();
5562 case GS_STATE_HUD_CONFIG:
5566 // join/start a game
5567 case GS_STATE_MULTI_JOIN_GAME:
5568 if(new_state != GS_STATE_OPTIONS_MENU){
5569 multi_join_game_close();
5573 case GS_STATE_MULTI_HOST_SETUP:
5574 case GS_STATE_MULTI_CLIENT_SETUP:
5575 // if this is just the host going into the options screen, don't do anything
5576 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5580 // close down the proper state
5581 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5582 multi_create_game_close();
5584 multi_game_client_setup_close();
5587 // COMMAND LINE OPTION
5588 if (Cmdline_multi_stream_chat_to_file){
5589 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5590 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5591 cfclose(Multi_chat_stream);
5596 case GS_STATE_CONTROL_CONFIG:
5597 control_config_close();
5600 case GS_STATE_DEATH_DIED:
5601 Game_mode &= ~GM_DEAD_DIED;
5603 // early end while respawning or blowing up in a multiplayer game
5604 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5606 freespace_stop_mission();
5610 case GS_STATE_DEATH_BLEW_UP:
5611 Game_mode &= ~GM_DEAD_BLEW_UP;
5613 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5614 // to determine if I should do anything.
5615 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5617 freespace_stop_mission();
5620 // if we are not respawing as an observer or as a player, our new state will not
5621 // be gameplay state.
5622 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5623 game_stop_time(); // hasn't been called yet!!
5624 freespace_stop_mission();
5630 case GS_STATE_CREDITS:
5634 case GS_STATE_VIEW_MEDALS:
5638 case GS_STATE_SHOW_GOALS:
5639 mission_show_goals_close();
5642 case GS_STATE_HOTKEY_SCREEN:
5643 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5644 mission_hotkey_close();
5648 case GS_STATE_MULTI_MISSION_SYNC:
5649 // if we're moving into the options menu, don't do anything
5650 if(new_state == GS_STATE_OPTIONS_MENU){
5654 Assert( Game_mode & GM_MULTIPLAYER );
5656 if ( new_state == GS_STATE_GAME_PLAY ){
5657 // palette_restore_palette();
5659 // change a couple of flags to indicate our state!!!
5660 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5661 send_netplayer_update_packet();
5663 // set the game mode
5664 Game_mode |= GM_IN_MISSION;
5668 case GS_STATE_VIEW_CUTSCENES:
5669 cutscenes_screen_close();
5672 case GS_STATE_MULTI_STD_WAIT:
5673 multi_standalone_wait_close();
5676 case GS_STATE_STANDALONE_MAIN:
5677 standalone_main_close();
5678 if(new_state == GS_STATE_MULTI_STD_WAIT){
5679 init_multiplayer_stats();
5683 case GS_STATE_MULTI_PAUSED:
5684 // if ( end_mission ){
5689 case GS_STATE_INGAME_PRE_JOIN:
5690 multi_ingame_select_close();
5693 case GS_STATE_STANDALONE_POSTGAME:
5694 multi_standalone_postgame_close();
5697 case GS_STATE_INITIAL_PLAYER_SELECT:
5698 player_select_close();
5701 case GS_STATE_MULTI_START_GAME:
5702 multi_start_game_close();
5705 case GS_STATE_MULTI_HOST_OPTIONS:
5706 multi_host_options_close();
5709 case GS_STATE_END_OF_CAMPAIGN:
5710 mission_campaign_end_close();
5713 case GS_STATE_LOOP_BRIEF:
5719 // Called when a state is being entered.
5720 // The current state is set to the state we're entering at
5721 // this point, and old_state is set to the state we're coming
5722 // from. You should never try to change the state
5723 // in here... if you think you need to, you probably really
5724 // need to post an event, not change the state.
5726 void game_enter_state( int old_state, int new_state )
5728 switch (new_state) {
5729 case GS_STATE_MAIN_MENU:
5730 // in multiplayer mode, be sure that we are not doing networking anymore.
5731 if ( Game_mode & GM_MULTIPLAYER ) {
5732 Assert( Net_player != NULL );
5733 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5736 Game_time_compression = F1_0;
5738 // determine which ship this guy is currently based on
5739 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5742 if (Player->on_bastion) {
5750 case GS_STATE_BRIEFING:
5751 main_hall_stop_music();
5752 main_hall_stop_ambient();
5754 if (Game_mode & GM_NORMAL) {
5755 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5756 // MWA: or from options or hotkey screens
5757 // JH: or if the command brief state already did this
5758 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5759 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5760 && (old_state != GS_STATE_CMD_BRIEF) ) {
5761 if ( !game_start_mission() ) // this should put us into a new state on failure!
5765 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5766 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5767 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5769 Game_time_compression = F1_0;
5771 if ( red_alert_mission() ) {
5772 gameseq_post_event(GS_EVENT_RED_ALERT);
5779 case GS_STATE_DEBRIEF:
5780 game_stop_looped_sounds();
5781 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5782 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5787 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5788 multi_df_debrief_init();
5791 case GS_STATE_LOAD_MISSION_MENU:
5792 mission_load_menu_init();
5795 case GS_STATE_SIMULATOR_ROOM:
5799 case GS_STATE_CAMPAIGN_ROOM:
5800 campaign_room_init();
5803 case GS_STATE_RED_ALERT:
5804 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5808 case GS_STATE_CMD_BRIEF: {
5809 int team_num = 0; // team number used as index for which cmd brief to use.
5811 if (old_state == GS_STATE_OPTIONS_MENU) {
5815 main_hall_stop_music();
5816 main_hall_stop_ambient();
5818 if (Game_mode & GM_NORMAL) {
5819 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5820 // MWA: or from options or hotkey screens
5821 // JH: or if the command brief state already did this
5822 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5823 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5824 if ( !game_start_mission() ) // this should put us into a new state on failure!
5829 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5830 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5831 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5833 cmd_brief_init(team_num);
5839 case GS_STATE_SHIP_SELECT:
5843 case GS_STATE_WEAPON_SELECT:
5844 weapon_select_init();
5847 case GS_STATE_TEAM_SELECT:
5851 case GS_STATE_GAME_PAUSED:
5856 case GS_STATE_DEBUG_PAUSED:
5857 // game_stop_time();
5858 // os_set_title("FreeSpace - PAUSED");
5861 case GS_STATE_TRAINING_PAUSED:
5868 case GS_STATE_OPTIONS_MENU:
5870 options_menu_init();
5873 case GS_STATE_GAME_PLAY:
5874 // coming from the gameplay state or the main menu, we might need to load the mission
5875 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5876 if ( !game_start_mission() ) // this should put us into a new state.
5881 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5882 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5883 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5884 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5885 (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) ) {
5886 // JAS: Used to do all paging here.
5890 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5894 main_hall_stop_music();
5895 main_hall_stop_ambient();
5896 event_music_first_pattern(); // start the first pattern
5899 // special code that restores player ship selection and weapons loadout when doing a quick start
5900 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5901 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5902 wss_direct_restore_loadout();
5906 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5907 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5908 event_music_first_pattern(); // start the first pattern
5911 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5912 event_music_first_pattern(); // start the first pattern
5914 player_restore_target_and_weapon_link_prefs();
5916 Game_mode |= GM_IN_MISSION;
5919 // required to truely make mouse deltas zeroed in debug mouse code
5920 void mouse_force_pos(int x, int y);
5921 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5926 // only start time if in single player, or coming from multi wait state
5929 (Game_mode & GM_NORMAL) &&
5930 (old_state != GS_STATE_VIEW_CUTSCENES)
5932 (Game_mode & GM_MULTIPLAYER) && (
5933 (old_state == GS_STATE_MULTI_PAUSED) ||
5934 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5940 // when coming from the multi paused state, reset the timestamps
5941 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5942 multi_reset_timestamps();
5945 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5946 // initialize all object update details
5947 multi_oo_gameplay_init();
5950 // under certain circumstances, the server should reset the object update rate limiting stuff
5951 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5952 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5954 // reinitialize the rate limiting system for all clients
5955 multi_oo_rate_init_all();
5958 // multiplayer clients should always re-initialize their control info rate limiting system
5959 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5960 multi_oo_rate_init_all();
5964 if(Game_mode & GM_MULTIPLAYER){
5965 multi_ping_reset_players();
5968 Game_subspace_effect = 0;
5969 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5970 Game_subspace_effect = 1;
5971 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5972 game_start_subspace_ambient_sound();
5976 sound_env_set(&Game_sound_env);
5977 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5979 // clear multiplayer button info i
5980 extern button_info Multi_ship_status_bi;
5981 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5984 case GS_STATE_HUD_CONFIG:
5988 case GS_STATE_MULTI_JOIN_GAME:
5989 multi_join_clear_game_list();
5991 if (old_state != GS_STATE_OPTIONS_MENU) {
5992 multi_join_game_init();
5997 case GS_STATE_MULTI_HOST_SETUP:
5998 // don't reinitialize if we're coming back from the host options screen
5999 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6000 multi_create_game_init();
6005 case GS_STATE_MULTI_CLIENT_SETUP:
6006 if (old_state != GS_STATE_OPTIONS_MENU) {
6007 multi_game_client_setup_init();
6012 case GS_STATE_CONTROL_CONFIG:
6013 control_config_init();
6016 case GS_STATE_TECH_MENU:
6020 case GS_STATE_BARRACKS_MENU:
6021 if(old_state != GS_STATE_VIEW_MEDALS){
6026 case GS_STATE_MISSION_LOG_SCROLLBACK:
6027 hud_scrollback_init();
6030 case GS_STATE_DEATH_DIED:
6031 Player_died_time = timestamp(10);
6033 if(!(Game_mode & GM_MULTIPLAYER)){
6034 player_show_death_message();
6036 Game_mode |= GM_DEAD_DIED;
6039 case GS_STATE_DEATH_BLEW_UP:
6040 if ( !popupdead_is_active() ) {
6041 Player_ai->target_objnum = -1;
6044 // stop any local EMP effect
6047 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6048 Game_mode |= GM_DEAD_BLEW_UP;
6049 Show_viewing_from_self = 0;
6051 // timestamp how long we should wait before displaying the died popup
6052 if ( !popupdead_is_active() ) {
6053 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6057 case GS_STATE_GAMEPLAY_HELP:
6058 gameplay_help_init();
6061 case GS_STATE_CREDITS:
6062 main_hall_stop_music();
6063 main_hall_stop_ambient();
6067 case GS_STATE_VIEW_MEDALS:
6068 medal_main_init(Player);
6071 case GS_STATE_SHOW_GOALS:
6072 mission_show_goals_init();
6075 case GS_STATE_HOTKEY_SCREEN:
6076 mission_hotkey_init();
6079 case GS_STATE_MULTI_MISSION_SYNC:
6080 // if we're coming from the options screen, don't do any
6081 if(old_state == GS_STATE_OPTIONS_MENU){
6085 switch(Multi_sync_mode){
6086 case MULTI_SYNC_PRE_BRIEFING:
6087 // if moving from game forming to the team select state
6090 case MULTI_SYNC_POST_BRIEFING:
6091 // if moving from briefing into the mission itself
6094 // tell everyone that we're now loading data
6095 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6096 send_netplayer_update_packet();
6098 // JAS: Used to do all paging here!!!!
6100 Net_player->state = NETPLAYER_STATE_WAITING;
6101 send_netplayer_update_packet();
6103 Game_time_compression = F1_0;
6105 case MULTI_SYNC_INGAME:
6111 case GS_STATE_VIEW_CUTSCENES:
6112 cutscenes_screen_init();
6115 case GS_STATE_MULTI_STD_WAIT:
6116 multi_standalone_wait_init();
6119 case GS_STATE_STANDALONE_MAIN:
6120 // don't initialize if we're coming from one of these 2 states unless there are no
6121 // players left (reset situation)
6122 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6123 standalone_main_init();
6127 case GS_STATE_MULTI_PAUSED:
6131 case GS_STATE_INGAME_PRE_JOIN:
6132 multi_ingame_select_init();
6135 case GS_STATE_STANDALONE_POSTGAME:
6136 multi_standalone_postgame_init();
6139 case GS_STATE_INITIAL_PLAYER_SELECT:
6140 player_select_init();
6143 case GS_STATE_MULTI_START_GAME:
6144 multi_start_game_init();
6147 case GS_STATE_MULTI_HOST_OPTIONS:
6148 multi_host_options_init();
6151 case GS_STATE_END_OF_CAMPAIGN:
6152 mission_campaign_end_init();
6155 case GS_STATE_LOOP_BRIEF:
6162 // do stuff that may need to be done regardless of state
6163 void game_do_state_common(int state,int no_networking)
6165 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6166 snd_do_frame(); // update sound system
6167 event_music_do_frame(); // music needs to play across many states
6169 multi_log_process();
6171 if (no_networking) {
6175 // maybe do a multiplayer frame based on game mode and state type
6176 if (Game_mode & GM_MULTIPLAYER) {
6178 case GS_STATE_OPTIONS_MENU:
6179 case GS_STATE_GAMEPLAY_HELP:
6180 case GS_STATE_HOTKEY_SCREEN:
6181 case GS_STATE_HUD_CONFIG:
6182 case GS_STATE_CONTROL_CONFIG:
6183 case GS_STATE_MISSION_LOG_SCROLLBACK:
6184 case GS_STATE_SHOW_GOALS:
6185 case GS_STATE_VIEW_CUTSCENES:
6186 case GS_STATE_EVENT_DEBUG:
6187 multi_maybe_do_frame();
6191 game_do_networking();
6195 // Called once a frame.
6196 // You should never try to change the state
6197 // in here... if you think you need to, you probably really
6198 // need to post an event, not change the state.
6199 int Game_do_state_should_skip = 0;
6200 void game_do_state(int state)
6202 // always lets the do_state_common() function determine if the state should be skipped
6203 Game_do_state_should_skip = 0;
6205 // legal to set the should skip state anywhere in this function
6206 game_do_state_common(state); // do stuff that may need to be done regardless of state
6208 if(Game_do_state_should_skip){
6213 case GS_STATE_MAIN_MENU:
6214 game_set_frametime(GS_STATE_MAIN_MENU);
6215 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6218 main_hall_do(flFrametime);
6222 case GS_STATE_OPTIONS_MENU:
6223 game_set_frametime(GS_STATE_OPTIONS_MENU);
6224 options_menu_do_frame(flFrametime);
6227 case GS_STATE_BARRACKS_MENU:
6228 game_set_frametime(GS_STATE_BARRACKS_MENU);
6229 barracks_do_frame(flFrametime);
6232 case GS_STATE_TRAINING_MENU:
6233 game_set_frametime(GS_STATE_TRAINING_MENU);
6234 training_menu_do_frame(flFrametime);
6237 case GS_STATE_TECH_MENU:
6238 game_set_frametime(GS_STATE_TECH_MENU);
6239 techroom_do_frame(flFrametime);
6242 case GS_STATE_GAMEPLAY_HELP:
6243 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6244 gameplay_help_do_frame(flFrametime);
6247 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6251 case GS_STATE_GAME_PAUSED:
6255 case GS_STATE_DEBUG_PAUSED:
6257 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6262 case GS_STATE_TRAINING_PAUSED:
6263 game_training_pause_do();
6266 case GS_STATE_LOAD_MISSION_MENU:
6267 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6268 mission_load_menu_do();
6271 case GS_STATE_BRIEFING:
6272 game_set_frametime(GS_STATE_BRIEFING);
6273 brief_do_frame(flFrametime);
6276 case GS_STATE_DEBRIEF:
6277 game_set_frametime(GS_STATE_DEBRIEF);
6278 debrief_do_frame(flFrametime);
6281 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6282 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6283 multi_df_debrief_do();
6286 case GS_STATE_SHIP_SELECT:
6287 game_set_frametime(GS_STATE_SHIP_SELECT);
6288 ship_select_do(flFrametime);
6291 case GS_STATE_WEAPON_SELECT:
6292 game_set_frametime(GS_STATE_WEAPON_SELECT);
6293 weapon_select_do(flFrametime);
6296 case GS_STATE_MISSION_LOG_SCROLLBACK:
6297 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6298 hud_scrollback_do_frame(flFrametime);
6301 case GS_STATE_HUD_CONFIG:
6302 game_set_frametime(GS_STATE_HUD_CONFIG);
6303 hud_config_do_frame(flFrametime);
6306 case GS_STATE_MULTI_JOIN_GAME:
6307 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6308 multi_join_game_do_frame();
6311 case GS_STATE_MULTI_HOST_SETUP:
6312 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6313 multi_create_game_do();
6316 case GS_STATE_MULTI_CLIENT_SETUP:
6317 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6318 multi_game_client_setup_do_frame();
6321 case GS_STATE_CONTROL_CONFIG:
6322 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6323 control_config_do_frame(flFrametime);
6326 case GS_STATE_DEATH_DIED:
6330 case GS_STATE_DEATH_BLEW_UP:
6334 case GS_STATE_SIMULATOR_ROOM:
6335 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6336 sim_room_do_frame(flFrametime);
6339 case GS_STATE_CAMPAIGN_ROOM:
6340 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6341 campaign_room_do_frame(flFrametime);
6344 case GS_STATE_RED_ALERT:
6345 game_set_frametime(GS_STATE_RED_ALERT);
6346 red_alert_do_frame(flFrametime);
6349 case GS_STATE_CMD_BRIEF:
6350 game_set_frametime(GS_STATE_CMD_BRIEF);
6351 cmd_brief_do_frame(flFrametime);
6354 case GS_STATE_CREDITS:
6355 game_set_frametime(GS_STATE_CREDITS);
6356 credits_do_frame(flFrametime);
6359 case GS_STATE_VIEW_MEDALS:
6360 game_set_frametime(GS_STATE_VIEW_MEDALS);
6364 case GS_STATE_SHOW_GOALS:
6365 game_set_frametime(GS_STATE_SHOW_GOALS);
6366 mission_show_goals_do_frame(flFrametime);
6369 case GS_STATE_HOTKEY_SCREEN:
6370 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6371 mission_hotkey_do_frame(flFrametime);
6374 case GS_STATE_VIEW_CUTSCENES:
6375 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6376 cutscenes_screen_do_frame();
6379 case GS_STATE_MULTI_STD_WAIT:
6380 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6381 multi_standalone_wait_do();
6384 case GS_STATE_STANDALONE_MAIN:
6385 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6386 standalone_main_do();
6389 case GS_STATE_MULTI_PAUSED:
6390 game_set_frametime(GS_STATE_MULTI_PAUSED);
6394 case GS_STATE_TEAM_SELECT:
6395 game_set_frametime(GS_STATE_TEAM_SELECT);
6399 case GS_STATE_INGAME_PRE_JOIN:
6400 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6401 multi_ingame_select_do();
6404 case GS_STATE_EVENT_DEBUG:
6406 game_set_frametime(GS_STATE_EVENT_DEBUG);
6407 game_show_event_debug(flFrametime);
6411 case GS_STATE_STANDALONE_POSTGAME:
6412 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6413 multi_standalone_postgame_do();
6416 case GS_STATE_INITIAL_PLAYER_SELECT:
6417 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6421 case GS_STATE_MULTI_MISSION_SYNC:
6422 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6426 case GS_STATE_MULTI_START_GAME:
6427 game_set_frametime(GS_STATE_MULTI_START_GAME);
6428 multi_start_game_do();
6431 case GS_STATE_MULTI_HOST_OPTIONS:
6432 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6433 multi_host_options_do();
6436 case GS_STATE_END_OF_CAMPAIGN:
6437 mission_campaign_end_do();
6440 case GS_STATE_END_DEMO:
6441 game_set_frametime(GS_STATE_END_DEMO);
6442 end_demo_campaign_do();
6445 case GS_STATE_LOOP_BRIEF:
6446 game_set_frametime(GS_STATE_LOOP_BRIEF);
6450 } // end switch(gs_current_state)
6454 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6455 int game_do_ram_check(int ram_in_bytes)
6457 if ( ram_in_bytes < 30*1024*1024 ) {
6458 int allowed_to_run = 1;
6459 if ( ram_in_bytes < 25*1024*1024 ) {
6464 int Freespace_total_ram_MB;
6465 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6467 if ( allowed_to_run ) {
6469 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);
6473 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6474 if ( msgbox_rval == IDCANCEL ) {
6481 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);
6483 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6494 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6495 // If so, copy it over and remove the update directory.
6496 void game_maybe_update_launcher(char *exe_dir)
6499 char src_filename[MAX_PATH];
6500 char dest_filename[MAX_PATH];
6502 strcpy(src_filename, exe_dir);
6503 strcat(src_filename, NOX("\\update\\freespace.exe"));
6505 strcpy(dest_filename, exe_dir);
6506 strcat(dest_filename, NOX("\\freespace.exe"));
6508 // see if src_filename exists
6510 fp = fopen(src_filename, "rb");
6516 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6518 // copy updated freespace.exe to freespace exe dir
6519 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6520 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 );
6524 // delete the file in the update directory
6525 DeleteFile(src_filename);
6527 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6528 char update_dir[MAX_PATH];
6529 strcpy(update_dir, exe_dir);
6530 strcat(update_dir, NOX("\\update"));
6531 RemoveDirectory(update_dir);
6537 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6541 int sub_total_destroyed = 0;
6545 // get the total for all his children
6546 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6547 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6550 // find the # of faces for this _individual_ object
6551 total = submodel_get_num_polys(model_num, sm);
6552 if(strstr(pm->submodel[sm].name, "-destroyed")){
6553 sub_total_destroyed = total;
6557 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6560 *out_total += total + sub_total;
6561 *out_destroyed_total += sub_total_destroyed;
6564 #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);
6565 void game_spew_pof_info()
6567 char *pof_list[1000];
6570 int idx, model_num, i, j;
6572 int total, root_total, model_total, destroyed_total, counted;
6576 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6578 // spew info on all the pofs
6584 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6589 for(idx=0; idx<num_files; idx++, counted++){
6590 sprintf(str, "%s.pof", pof_list[idx]);
6591 model_num = model_load(str, 0, NULL);
6593 pm = model_get(model_num);
6595 // if we have a real model
6600 // go through and print all raw submodels
6601 cfputs("RAW\n", out);
6604 for (i=0; i<pm->n_models; i++) {
6605 total = submodel_get_num_polys(model_num, i);
6607 model_total += total;
6608 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6611 sprintf(str, "Model total %d\n", model_total);
6614 // now go through and do it by LOD
6615 cfputs("BY LOD\n\n", out);
6616 for(i=0; i<pm->n_detail_levels; i++){
6617 sprintf(str, "LOD %d\n", i);
6621 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6623 destroyed_total = 0;
6624 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6625 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6628 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6631 sprintf(str, "TOTAL: %d\n", total + root_total);
6633 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6635 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6638 cfputs("------------------------------------------------------------------------\n\n", out);
6642 if(counted >= MAX_POLYGON_MODELS - 5){
6655 game_spew_pof_info();
6658 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6663 // Don't let more than one instance of Freespace run.
6664 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6666 SetForegroundWindow(hwnd);
6671 // Find out how much RAM is on this machine
6674 ms.dwLength = sizeof(MEMORYSTATUS);
6675 GlobalMemoryStatus(&ms);
6676 Freespace_total_ram = ms.dwTotalPhys;
6678 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6682 if ( ms.dwTotalVirtual < 1024 ) {
6683 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6687 if (!vm_init(24*1024*1024)) {
6688 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 );
6692 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6694 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);
6704 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6705 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6706 seem worth bothering with.
6710 lResult = RegOpenKeyEx(
6711 HKEY_LOCAL_MACHINE, // Where it is
6712 "Software\\Microsoft\\DirectX", // name of key
6713 NULL, // DWORD reserved
6714 KEY_QUERY_VALUE, // Allows all changes
6715 &hKey // Location to store key
6718 if (lResult == ERROR_SUCCESS) {
6720 DWORD dwType, dwLen;
6723 lResult = RegQueryValueEx(
6724 hKey, // Handle to key
6725 "Version", // The values name
6726 NULL, // DWORD reserved
6727 &dwType, // What kind it is
6728 (ubyte *) version, // value to set
6729 &dwLen // How many bytes to set
6732 if (lResult == ERROR_SUCCESS) {
6733 dx_version = atoi(strstr(version, ".") + 1);
6737 DWORD dwType, dwLen;
6740 lResult = RegQueryValueEx(
6741 hKey, // Handle to key
6742 "InstalledVersion", // The values name
6743 NULL, // DWORD reserved
6744 &dwType, // What kind it is
6745 (ubyte *) &val, // value to set
6746 &dwLen // How many bytes to set
6749 if (lResult == ERROR_SUCCESS) {
6757 if (dx_version < 3) {
6758 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6759 "latest version of DirectX at:\n\n"
6760 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6762 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6763 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6768 //=====================================================
6769 // Make sure we're running in the right directory.
6773 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6774 char *p = exe_dir + strlen(exe_dir);
6776 // chop off the filename
6777 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6783 if ( strlen(exe_dir) > 0 ) {
6784 SetCurrentDirectory(exe_dir);
6787 // check for updated freespace.exe
6788 game_maybe_update_launcher(exe_dir);
6796 extern void windebug_memwatch_init();
6797 windebug_memwatch_init();
6801 parse_cmdline(szCmdLine);
6803 #ifdef STANDALONE_ONLY_BUILD
6805 nprintf(("Network", "Standalone running"));
6808 nprintf(("Network", "Standalone running"));
6816 // maybe spew pof stuff
6817 if(Cmdline_spew_pof_info){
6818 game_spew_pof_info();
6823 // non-demo, non-standalone, play the intro movie
6828 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) ){
6830 #if defined(OEM_BUILD)
6831 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6833 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6834 #endif // defined(OEM_BUILD)
6839 if ( !Is_standalone ) {
6841 // release -- movies always play
6844 // 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
6846 // movie_play( NOX("intro.mve"), 0 );
6848 // debug version, movie will only play with -showmovies
6849 #elif !defined(NDEBUG)
6852 // movie_play( NOX("intro.mve"), 0);
6855 if ( Cmdline_show_movies )
6856 movie_play( NOX("intro.mve"), 0 );
6865 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6867 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6871 // only important for non THREADED mode
6874 state = gameseq_process_events();
6875 if ( state == GS_STATE_QUIT_GAME ){
6882 demo_upsell_show_screens();
6884 #elif defined(OEM_BUILD)
6885 // show upsell screens on exit
6886 oem_upsell_show_screens();
6893 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6899 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6901 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6903 // Do nothing here - RecordExceptionInfo() has already done
6904 // everything that is needed. Actually this code won't even
6905 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6906 // the __except clause.
6912 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6913 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6919 // launcher the fslauncher program on exit
6920 void game_launch_launcher_on_exit()
6924 PROCESS_INFORMATION pi;
6925 char cmd_line[2048];
6926 char original_path[1024] = "";
6928 memset( &si, 0, sizeof(STARTUPINFO) );
6932 _getcwd(original_path, 1023);
6934 // set up command line
6935 strcpy(cmd_line, original_path);
6936 strcat(cmd_line, "\\");
6937 strcat(cmd_line, LAUNCHER_FNAME);
6938 strcat(cmd_line, " -straight_to_update");
6940 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6941 cmd_line, // pointer to command line string
6942 NULL, // pointer to process security attributes
6943 NULL, // pointer to thread security attributes
6944 FALSE, // handle inheritance flag
6945 CREATE_DEFAULT_ERROR_MODE, // creation flags
6946 NULL, // pointer to new environment block
6947 NULL, // pointer to current directory name
6948 &si, // pointer to STARTUPINFO
6949 &pi // pointer to PROCESS_INFORMATION
6951 // to eliminate build warnings
6961 // This function is called when FreeSpace terminates normally.
6963 void game_shutdown(void)
6969 // don't ever flip a page on the standalone!
6970 if(!(Game_mode & GM_STANDALONE_SERVER)){
6976 // if the player has left the "player select" screen and quit the game without actually choosing
6977 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6978 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6982 // load up common multiplayer icons
6983 multi_unload_common_icons();
6985 shockwave_close(); // release any memory used by shockwave system
6986 fireball_close(); // free fireball system
6987 ship_close(); // free any memory that was allocated for the ships
6988 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6989 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6990 bm_unload_all(); // free bitmaps
6991 mission_campaign_close(); // close out the campaign stuff
6992 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6994 #ifdef MULTI_USE_LAG
6998 // the menu close functions will unload the bitmaps if they were displayed during the game
6999 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7002 training_menu_close();
7005 extern void joy_close();
7008 audiostream_close();
7010 event_music_close();
7014 // HACKITY HACK HACK
7015 // if this flag is set, we should be firing up the launcher when exiting freespace
7016 extern int Multi_update_fireup_launcher_on_exit;
7017 if(Multi_update_fireup_launcher_on_exit){
7018 game_launch_launcher_on_exit();
7022 // game_stop_looped_sounds()
7024 // This function will call the appropriate stop looped sound functions for those
7025 // modules which use looping sounds. It is not enough just to stop a looping sound
7026 // at the DirectSound level, the game is keeping track of looping sounds, and this
7027 // function is used to inform the game that looping sounds are being halted.
7029 void game_stop_looped_sounds()
7031 hud_stop_looped_locking_sounds();
7032 hud_stop_looped_engine_sounds();
7033 afterburner_stop_sounds();
7034 player_stop_looped_sounds();
7035 obj_snd_stop_all(); // stop all object-linked persistant sounds
7036 game_stop_subspace_ambient_sound();
7037 snd_stop(Radar_static_looping);
7038 Radar_static_looping = -1;
7039 snd_stop(Target_static_looping);
7040 shipfx_stop_engine_wash_sound();
7041 Target_static_looping = -1;
7044 //////////////////////////////////////////////////////////////////////////
7046 // Code for supporting an animating mouse pointer
7049 //////////////////////////////////////////////////////////////////////////
7051 typedef struct animating_obj
7060 static animating_obj Animating_mouse;
7062 // ----------------------------------------------------------------------------
7063 // init_animating_pointer()
7065 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7066 // gets properly initialized
7068 void init_animating_pointer()
7070 Animating_mouse.first_frame = -1;
7071 Animating_mouse.num_frames = 0;
7072 Animating_mouse.current_frame = -1;
7073 Animating_mouse.time = 0.0f;
7074 Animating_mouse.elapsed_time = 0.0f;
7077 // ----------------------------------------------------------------------------
7078 // load_animating_pointer()
7080 // Called at game init to load in the frames for the animating mouse pointer
7082 // input: filename => filename of animation file that holds the animation
7084 void load_animating_pointer(char *filename, int dx, int dy)
7089 init_animating_pointer();
7091 am = &Animating_mouse;
7092 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7093 if ( am->first_frame == -1 )
7094 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7095 am->current_frame = 0;
7096 am->time = am->num_frames / i2fl(fps);
7099 // ----------------------------------------------------------------------------
7100 // unload_animating_pointer()
7102 // Called at game shutdown to free the memory used to store the animation frames
7104 void unload_animating_pointer()
7109 am = &Animating_mouse;
7110 for ( i = 0; i < am->num_frames; i++ ) {
7111 Assert( (am->first_frame+i) >= 0 );
7112 bm_release(am->first_frame + i);
7115 am->first_frame = -1;
7117 am->current_frame = -1;
7120 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7121 void game_render_mouse(float frametime)
7126 // if animating cursor exists, play the next frame
7127 am = &Animating_mouse;
7128 if ( am->first_frame != -1 ) {
7129 mouse_get_pos(&mx, &my);
7130 am->elapsed_time += frametime;
7131 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7132 if ( am->current_frame >= am->num_frames ) {
7133 am->current_frame = 0;
7134 am->elapsed_time = 0.0f;
7136 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7140 // ----------------------------------------------------------------------------
7141 // game_maybe_draw_mouse()
7143 // determines whether to draw the mouse pointer at all, and what frame of
7144 // animation to use if the mouse is animating
7146 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7148 // input: frametime => elapsed frame time in seconds since last call
7150 void game_maybe_draw_mouse(float frametime)
7154 game_state = gameseq_get_state();
7156 switch ( game_state ) {
7157 case GS_STATE_GAME_PAUSED:
7158 // case GS_STATE_MULTI_PAUSED:
7159 case GS_STATE_GAME_PLAY:
7160 case GS_STATE_DEATH_DIED:
7161 case GS_STATE_DEATH_BLEW_UP:
7162 if ( popup_active() || popupdead_is_active() ) {
7174 if ( !Mouse_hidden )
7175 game_render_mouse(frametime);
7179 void game_do_training_checks()
7183 waypoint_list *wplp;
7185 if (Training_context & TRAINING_CONTEXT_SPEED) {
7186 s = (int) Player_obj->phys_info.fspeed;
7187 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7188 if (!Training_context_speed_set) {
7189 Training_context_speed_set = 1;
7190 Training_context_speed_timestamp = timestamp();
7194 Training_context_speed_set = 0;
7197 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7198 wplp = &Waypoint_lists[Training_context_path];
7199 if (wplp->count > Training_context_goal_waypoint) {
7200 i = Training_context_goal_waypoint;
7202 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7203 if (d <= Training_context_distance) {
7204 Training_context_at_waypoint = i;
7205 if (Training_context_goal_waypoint == i) {
7206 Training_context_goal_waypoint++;
7207 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7214 if (i == wplp->count)
7217 } while (i != Training_context_goal_waypoint);
7221 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7222 Players_target = Player_ai->target_objnum;
7223 Players_targeted_subsys = Player_ai->targeted_subsys;
7224 Players_target_timestamp = timestamp();
7228 /////////// Following is for event debug view screen
7232 #define EVENT_DEBUG_MAX 5000
7233 #define EVENT_DEBUG_EVENT 0x8000
7235 int Event_debug_index[EVENT_DEBUG_MAX];
7238 void game_add_event_debug_index(int n, int indent)
7240 if (ED_count < EVENT_DEBUG_MAX)
7241 Event_debug_index[ED_count++] = n | (indent << 16);
7244 void game_add_event_debug_sexp(int n, int indent)
7249 if (Sexp_nodes[n].first >= 0) {
7250 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7251 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7255 game_add_event_debug_index(n, indent);
7256 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7257 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7259 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7262 void game_event_debug_init()
7267 for (e=0; e<Num_mission_events; e++) {
7268 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7269 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7273 void game_show_event_debug(float frametime)
7277 int font_height, font_width;
7279 static int scroll_offset = 0;
7281 k = game_check_key();
7287 if (scroll_offset < 0)
7297 scroll_offset -= 20;
7298 if (scroll_offset < 0)
7303 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7307 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7313 gr_set_color_fast(&Color_bright);
7315 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7317 gr_set_color_fast(&Color_normal);
7319 gr_get_string_size(&font_width, &font_height, NOX("test"));
7320 y_max = gr_screen.max_h - font_height - 5;
7324 while (k < ED_count) {
7325 if (y_index > y_max)
7328 z = Event_debug_index[k];
7329 if (z & EVENT_DEBUG_EVENT) {
7331 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7332 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7333 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7334 Mission_events[z].repeat_count, Mission_events[z].interval);
7342 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7343 switch (Sexp_nodes[z & 0x7fff].value) {
7345 strcat(buf, NOX(" (True)"));
7349 strcat(buf, NOX(" (False)"));
7352 case SEXP_KNOWN_TRUE:
7353 strcat(buf, NOX(" (Always true)"));
7356 case SEXP_KNOWN_FALSE:
7357 strcat(buf, NOX(" (Always false)"));
7360 case SEXP_CANT_EVAL:
7361 strcat(buf, NOX(" (Can't eval)"));
7365 case SEXP_NAN_FOREVER:
7366 strcat(buf, NOX(" (Not a number)"));
7371 gr_printf(10, y_index, buf);
7372 y_index += font_height;
7385 extern int Tmap_npixels;
7387 int Tmap_num_too_big = 0;
7388 int Num_models_needing_splitting = 0;
7390 void Time_model( int modelnum )
7392 // mprintf(( "Timing ship '%s'\n", si->name ));
7394 vector eye_pos, model_pos;
7395 matrix eye_orient, model_orient;
7397 polymodel *pm = model_get( modelnum );
7399 int l = strlen(pm->filename);
7401 if ( (l == '/') || (l=='\\') || (l==':')) {
7407 char *pof_file = &pm->filename[l];
7409 int model_needs_splitting = 0;
7411 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7413 for (i=0; i<pm->n_textures; i++ ) {
7414 char filename[1024];
7417 int bmp_num = pm->original_textures[i];
7418 if ( bmp_num > -1 ) {
7419 bm_get_palette(pm->original_textures[i], pal, filename );
7421 bm_get_info( pm->original_textures[i],&w, &h );
7424 if ( (w > 512) || (h > 512) ) {
7425 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7427 model_needs_splitting++;
7430 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7434 if ( model_needs_splitting ) {
7435 Num_models_needing_splitting++;
7437 eye_orient = model_orient = vmd_identity_matrix;
7438 eye_pos = model_pos = vmd_zero_vector;
7440 eye_pos.z = -pm->rad*2.0f;
7442 vector eye_to_model;
7444 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7445 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7447 fix t1 = timer_get_fixed_seconds();
7450 ta.p = ta.b = ta.h = 0.0f;
7455 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7457 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7459 modelstats_num_polys = modelstats_num_verts = 0;
7461 while( ta.h < PI2 ) {
7464 vm_angles_2_matrix(&m1, &ta );
7465 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7472 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7474 model_clear_instance( modelnum );
7475 model_set_detail_level(0); // use highest detail level
7476 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7484 int k = key_inkey();
7485 if ( k == KEY_ESC ) {
7490 fix t2 = timer_get_fixed_seconds();
7492 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7493 //bitmaps_used_this_frame /= framecount;
7495 modelstats_num_polys /= framecount;
7496 modelstats_num_verts /= framecount;
7498 Tmap_npixels /=framecount;
7501 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7502 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 );
7503 // 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 );
7509 int Time_models = 0;
7510 DCF_BOOL( time_models, Time_models );
7512 void Do_model_timings_test()
7516 if ( !Time_models ) return;
7518 mprintf(( "Timing models!\n" ));
7522 ubyte model_used[MAX_POLYGON_MODELS];
7523 int model_id[MAX_POLYGON_MODELS];
7524 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7529 for (i=0; i<Num_ship_types; i++ ) {
7530 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7532 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7533 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7536 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7537 if ( !Texture_fp ) return;
7539 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7540 if ( !Time_fp ) return;
7542 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7543 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7545 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7546 if ( model_used[i] ) {
7547 Time_model( model_id[i] );
7551 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7552 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7561 // Call this function when you want to inform the player that a feature is not
7562 // enabled in the DEMO version of FreSpace
7563 void game_feature_not_in_demo_popup()
7565 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7568 // format the specified time (fixed point) into a nice string
7569 void game_format_time(fix m_time,char *time_str)
7572 int hours,minutes,seconds;
7575 mtime = f2fl(m_time);
7577 // get the hours, minutes and seconds
7578 hours = (int)(mtime / 3600.0f);
7580 mtime -= (3600.0f * (float)hours);
7582 seconds = (int)mtime%60;
7583 minutes = (int)mtime/60;
7585 // print the hour if necessary
7587 sprintf(time_str,XSTR( "%d:", 201),hours);
7588 // if there are less than 10 minutes, print a leading 0
7590 strcpy(tmp,NOX("0"));
7591 strcat(time_str,tmp);
7595 // print the minutes
7597 sprintf(tmp,XSTR( "%d:", 201),minutes);
7598 strcat(time_str,tmp);
7600 sprintf(time_str,XSTR( "%d:", 201),minutes);
7603 // print the seconds
7605 strcpy(tmp,NOX("0"));
7606 strcat(time_str,tmp);
7608 sprintf(tmp,"%d",seconds);
7609 strcat(time_str,tmp);
7612 // Stuff version string in *str.
7613 void get_version_string(char *str)
7616 if ( FS_VERSION_BUILD == 0 ) {
7617 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7619 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7622 #if defined (FS2_DEMO)
7624 #elif defined (OEM_BUILD)
7625 strcat(str, " (OEM)");
7631 char myname[_MAX_PATH];
7632 int namelen, major, minor, build, waste;
7633 unsigned int buf_size;
7639 // Find my EXE file name
7640 hMod = GetModuleHandle(NULL);
7641 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7643 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7644 infop = (char *)malloc(version_size);
7645 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7647 // get the product version
7648 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7649 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7651 sprintf(str,"Dv%d.%02d",major, minor);
7653 sprintf(str,"v%d.%02d",major, minor);
7658 void get_version_string_short(char *str)
7660 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7663 // ----------------------------------------------------------------
7665 // OEM UPSELL SCREENS BEGIN
7667 // ----------------------------------------------------------------
7668 #if defined(OEM_BUILD)
7670 #define NUM_OEM_UPSELL_SCREENS 3
7671 #define OEM_UPSELL_SCREEN_DELAY 10000
7673 static int Oem_upsell_bitmaps_loaded = 0;
7674 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7675 static int Oem_upsell_screen_number = 0;
7676 static int Oem_upsell_show_next_bitmap_time;
7679 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7692 static int Oem_normal_cursor = -1;
7693 static int Oem_web_cursor = -1;
7694 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7695 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7697 void oem_upsell_next_screen()
7699 Oem_upsell_screen_number++;
7700 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7701 // extra long delay, mouse shown on last upsell
7702 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7706 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7710 void oem_upsell_load_bitmaps()
7714 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7715 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7719 void oem_upsell_unload_bitmaps()
7723 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7724 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7725 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7730 Oem_upsell_bitmaps_loaded = 0;
7733 // clickable hotspot on 3rd OEM upsell screen
7734 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7736 28, 350, 287, 96 // x, y, w, h
7739 45, 561, 460, 152 // x, y, w, h
7743 void oem_upsell_show_screens()
7745 int current_time, k;
7748 if ( !Oem_upsell_bitmaps_loaded ) {
7749 oem_upsell_load_bitmaps();
7750 Oem_upsell_bitmaps_loaded = 1;
7753 // may use upsell screens more than once
7754 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7755 Oem_upsell_screen_number = 0;
7761 int nframes; // used to pass, not really needed (should be 1)
7762 Oem_normal_cursor = gr_get_cursor_bitmap();
7763 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7764 Assert(Oem_web_cursor >= 0);
7765 if (Oem_web_cursor < 0) {
7766 Oem_web_cursor = Oem_normal_cursor;
7771 //oem_reset_trailer_timer();
7773 current_time = timer_get_milliseconds();
7778 // advance screen on keypress or timeout
7779 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7780 oem_upsell_next_screen();
7783 // check if we are done
7784 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7785 Oem_upsell_screen_number--;
7788 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7793 // show me the upsell
7794 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7795 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7799 // if this is the 3rd upsell, make it clickable, d00d
7800 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7802 int button_state = mouse_get_pos(&mx, &my);
7803 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])
7804 && (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]) )
7807 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7810 if (button_state & MOUSE_LEFT_BUTTON) {
7812 multi_pxo_url(OEM_UPSELL_URL);
7816 // switch cursor back to normal one
7817 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7822 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7832 oem_upsell_unload_bitmaps();
7834 // switch cursor back to normal one
7835 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7839 #endif // defined(OEM_BUILD)
7840 // ----------------------------------------------------------------
7842 // OEM UPSELL SCREENS END
7844 // ----------------------------------------------------------------
7848 // ----------------------------------------------------------------
7850 // DEMO UPSELL SCREENS BEGIN
7852 // ----------------------------------------------------------------
7856 //#define NUM_DEMO_UPSELL_SCREENS 4
7858 #define NUM_DEMO_UPSELL_SCREENS 2
7859 #define DEMO_UPSELL_SCREEN_DELAY 3000
7861 static int Demo_upsell_bitmaps_loaded = 0;
7862 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7863 static int Demo_upsell_screen_number = 0;
7864 static int Demo_upsell_show_next_bitmap_time;
7867 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7880 void demo_upsell_next_screen()
7882 Demo_upsell_screen_number++;
7883 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7884 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7886 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7890 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7891 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7892 #ifndef HARDWARE_ONLY
7893 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7900 void demo_upsell_load_bitmaps()
7904 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7905 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7909 void demo_upsell_unload_bitmaps()
7913 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7914 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7915 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7920 Demo_upsell_bitmaps_loaded = 0;
7923 void demo_upsell_show_screens()
7925 int current_time, k;
7928 if ( !Demo_upsell_bitmaps_loaded ) {
7929 demo_upsell_load_bitmaps();
7930 Demo_upsell_bitmaps_loaded = 1;
7933 // may use upsell screens more than once
7934 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7935 Demo_upsell_screen_number = 0;
7942 demo_reset_trailer_timer();
7944 current_time = timer_get_milliseconds();
7951 // don't time out, wait for keypress
7953 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7954 demo_upsell_next_screen();
7959 demo_upsell_next_screen();
7962 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7963 Demo_upsell_screen_number--;
7966 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7971 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7972 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7977 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7987 demo_upsell_unload_bitmaps();
7992 // ----------------------------------------------------------------
7994 // DEMO UPSELL SCREENS END
7996 // ----------------------------------------------------------------
7999 // ----------------------------------------------------------------
8001 // Subspace Ambient Sound START
8003 // ----------------------------------------------------------------
8005 static int Subspace_ambient_left_channel = -1;
8006 static int Subspace_ambient_right_channel = -1;
8009 void game_start_subspace_ambient_sound()
8011 if ( Subspace_ambient_left_channel < 0 ) {
8012 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8015 if ( Subspace_ambient_right_channel < 0 ) {
8016 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8020 void game_stop_subspace_ambient_sound()
8022 if ( Subspace_ambient_left_channel >= 0 ) {
8023 snd_stop(Subspace_ambient_left_channel);
8024 Subspace_ambient_left_channel = -1;
8027 if ( Subspace_ambient_right_channel >= 0 ) {
8028 snd_stop(Subspace_ambient_right_channel);
8029 Subspace_ambient_right_channel = -1;
8033 // ----------------------------------------------------------------
8035 // Subspace Ambient Sound END
8037 // ----------------------------------------------------------------
8039 // ----------------------------------------------------------------
8041 // CDROM detection code START
8043 // ----------------------------------------------------------------
8045 #define CD_SIZE_72_MINUTE_MAX (697000000)
8047 uint game_get_cd_used_space(char *path)
8051 char use_path[512] = "";
8052 char sub_path[512] = "";
8053 WIN32_FIND_DATA find;
8056 // recurse through all files and directories
8057 strcpy(use_path, path);
8058 strcat(use_path, "*.*");
8059 find_handle = FindFirstFile(use_path, &find);
8062 if(find_handle == INVALID_HANDLE_VALUE){
8068 // subdirectory. make sure to ignore . and ..
8069 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8071 strcpy(sub_path, path);
8072 strcat(sub_path, find.cFileName);
8073 strcat(sub_path, "\\");
8074 total += game_get_cd_used_space(sub_path);
8076 total += (uint)find.nFileSizeLow;
8078 } while(FindNextFile(find_handle, &find));
8081 FindClose(find_handle);
8093 // if volume_name is non-null, the CD name must match that
8094 int find_freespace_cd(char *volume_name)
8097 char oldpath[MAX_PATH];
8101 int volume_match = 0;
8105 GetCurrentDirectory(MAX_PATH, oldpath);
8107 for (i = 0; i < 26; i++)
8113 path[0] = (char)('A'+i);
8114 if (GetDriveType(path) == DRIVE_CDROM) {
8116 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8117 nprintf(("CD", "CD volume: %s\n", volume));
8119 // check for any CD volume
8120 int volume1_present = 0;
8121 int volume2_present = 0;
8122 int volume3_present = 0;
8124 char full_check[512] = "";
8126 // look for setup.exe
8127 strcpy(full_check, path);
8128 strcat(full_check, "setup.exe");
8129 find_handle = _findfirst(full_check, &find);
8130 if(find_handle != -1){
8131 volume1_present = 1;
8132 _findclose(find_handle);
8135 // look for intro.mve
8136 strcpy(full_check, path);
8137 strcat(full_check, "intro.mve");
8138 find_handle = _findfirst(full_check, &find);
8139 if(find_handle != -1){
8140 volume2_present = 1;
8141 _findclose(find_handle);
8144 // look for endpart1.mve
8145 strcpy(full_check, path);
8146 strcat(full_check, "endpart1.mve");
8147 find_handle = _findfirst(full_check, &find);
8148 if(find_handle != -1){
8149 volume3_present = 1;
8150 _findclose(find_handle);
8153 // see if we have the specific CD we're looking for
8154 if ( volume_name ) {
8156 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8160 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8164 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8168 if ( volume1_present || volume2_present || volume3_present ) {
8173 // 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
8174 if ( volume_match ){
8176 // 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
8177 if(volume2_present || volume3_present) {
8178 // first step - check to make sure its a cdrom
8179 if(GetDriveType(path) != DRIVE_CDROM){
8183 #if !defined(OEM_BUILD)
8184 // oem not on 80 min cds, so dont check tha size
8186 uint used_space = game_get_cd_used_space(path);
8187 if(used_space < CD_SIZE_72_MINUTE_MAX){
8190 #endif // !defined(OEM_BUILD)
8198 #endif // RELEASE_REAL
8204 SetCurrentDirectory(oldpath);
8213 int set_cdrom_path(int drive_num)
8217 if (drive_num < 0) { //no CD
8219 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8222 strcpy(Game_CDROM_dir,""); //set directory
8226 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8242 i = find_freespace_cd();
8244 rval = set_cdrom_path(i);
8248 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8250 nprintf(("CD", "FreeSpace CD not found\n"));
8258 int Last_cd_label_found = 0;
8259 char Last_cd_label[256];
8261 int game_cd_changed()
8268 if ( strlen(Game_CDROM_dir) == 0 ) {
8272 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8274 if ( found != Last_cd_label_found ) {
8275 Last_cd_label_found = found;
8277 mprintf(( "CD '%s' was inserted\n", label ));
8280 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8284 if ( Last_cd_label_found ) {
8285 if ( !stricmp( Last_cd_label, label )) {
8286 //mprintf(( "CD didn't change\n" ));
8288 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8292 // none found before, none found now.
8293 //mprintf(( "still no CD...\n" ));
8297 Last_cd_label_found = found;
8299 strcpy( Last_cd_label, label );
8301 strcpy( Last_cd_label, "" );
8312 // check if _any_ FreeSpace2 CDs are in the drive
8313 // return: 1 => CD now in drive
8314 // 0 => Could not find CD, they refuse to put it in the drive
8315 int game_do_cd_check(char *volume_name)
8317 #if !defined(GAME_CD_CHECK)
8323 int num_attempts = 0;
8324 int refresh_files = 0;
8326 int path_set_ok, popup_rval;
8328 cd_drive_num = find_freespace_cd(volume_name);
8329 path_set_ok = set_cdrom_path(cd_drive_num);
8330 if ( path_set_ok ) {
8332 if ( refresh_files ) {
8344 // no CD found, so prompt user
8345 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8347 if ( popup_rval != 1 ) {
8352 if ( num_attempts++ > 5 ) {
8363 // check if _any_ FreeSpace2 CDs are in the drive
8364 // return: 1 => CD now in drive
8365 // 0 => Could not find CD, they refuse to put it in the drive
8366 int game_do_cd_check_specific(char *volume_name, int cdnum)
8371 int num_attempts = 0;
8372 int refresh_files = 0;
8374 int path_set_ok, popup_rval;
8376 cd_drive_num = find_freespace_cd(volume_name);
8377 path_set_ok = set_cdrom_path(cd_drive_num);
8378 if ( path_set_ok ) {
8380 if ( refresh_files ) {
8391 // no CD found, so prompt user
8392 #if defined(DVD_MESSAGE_HACK)
8393 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8395 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8398 if ( popup_rval != 1 ) {
8403 if ( num_attempts++ > 5 ) {
8413 // only need to do this in RELEASE_REAL
8414 int game_do_cd_mission_check(char *filename)
8420 fs_builtin_mission *m = game_find_builtin_mission(filename);
8422 // check for changed CD
8423 if(game_cd_changed()){
8428 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8432 // not builtin, so do a general check (any FS2 CD will do)
8434 return game_do_cd_check();
8437 // does not have any CD requirement, do a general check
8438 if(strlen(m->cd_volume) <= 0){
8439 return game_do_cd_check();
8443 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8445 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8447 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8450 return game_do_cd_check();
8453 // did we find the cd?
8454 if(find_freespace_cd(m->cd_volume) >= 0){
8458 // make sure the volume exists
8459 int num_attempts = 0;
8460 int refresh_files = 0;
8462 int path_set_ok, popup_rval;
8464 cd_drive_num = find_freespace_cd(m->cd_volume);
8465 path_set_ok = set_cdrom_path(cd_drive_num);
8466 if ( path_set_ok ) {
8468 if ( refresh_files ) {
8475 // no CD found, so prompt user
8476 #if defined(DVD_MESSAGE_HACK)
8477 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8479 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8483 if ( popup_rval != 1 ) {
8488 if ( num_attempts++ > 5 ) {
8500 // ----------------------------------------------------------------
8502 // CDROM detection code END
8504 // ----------------------------------------------------------------
8506 // ----------------------------------------------------------------
8507 // SHIPS TBL VERIFICATION STUFF
8510 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8511 #define NUM_SHIPS_TBL_CHECKSUMS 1
8513 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8514 -463907578, // US - beta 1
8515 1696074201, // FS2 demo
8518 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8519 // -1022810006, // 1.0 FULL
8520 -1254285366 // 1.2 FULL (German)
8523 void verify_ships_tbl()
8527 Game_ships_tbl_valid = 1;
8533 // detect if the packfile exists
8534 CFILE *detect = cfopen("ships.tbl", "rb");
8535 Game_ships_tbl_valid = 0;
8539 Game_ships_tbl_valid = 0;
8543 // get the long checksum of the file
8545 cfseek(detect, 0, SEEK_SET);
8546 cf_chksum_long(detect, &file_checksum);
8550 // now compare the checksum/filesize against known #'s
8551 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8552 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8553 Game_ships_tbl_valid = 1;
8560 DCF(shipspew, "display the checksum for the current ships.tbl")
8563 CFILE *detect = cfopen("ships.tbl", "rb");
8564 // get the long checksum of the file
8566 cfseek(detect, 0, SEEK_SET);
8567 cf_chksum_long(detect, &file_checksum);
8570 dc_printf("%d", file_checksum);
8573 // ----------------------------------------------------------------
8574 // WEAPONS TBL VERIFICATION STUFF
8577 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8578 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8580 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8581 141718090, // US - beta 1
8582 -266420030, // demo 1
8585 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8586 // 399297860, // 1.0 FULL
8587 -553984927 // 1.2 FULL (german)
8590 void verify_weapons_tbl()
8594 Game_weapons_tbl_valid = 1;
8600 // detect if the packfile exists
8601 CFILE *detect = cfopen("weapons.tbl", "rb");
8602 Game_weapons_tbl_valid = 0;
8606 Game_weapons_tbl_valid = 0;
8610 // get the long checksum of the file
8612 cfseek(detect, 0, SEEK_SET);
8613 cf_chksum_long(detect, &file_checksum);
8617 // now compare the checksum/filesize against known #'s
8618 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8619 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8620 Game_weapons_tbl_valid = 1;
8627 DCF(wepspew, "display the checksum for the current weapons.tbl")
8630 CFILE *detect = cfopen("weapons.tbl", "rb");
8631 // get the long checksum of the file
8633 cfseek(detect, 0, SEEK_SET);
8634 cf_chksum_long(detect, &file_checksum);
8637 dc_printf("%d", file_checksum);
8640 // if the game is running using hacked data
8641 int game_hacked_data()
8644 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8652 void display_title_screen()
8654 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8655 ///int title_bitmap;
8658 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8659 if (title_bitmap == -1) {
8664 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8665 extern void d3d_start_frame();
8670 gr_set_bitmap(title_bitmap);
8676 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8677 extern void d3d_stop_frame();
8684 bm_unload(title_bitmap);
8685 #endif // FS2_DEMO || OEM_BUILD
8688 // return true if the game is running with "low memory", which is less than 48MB
8689 bool game_using_low_mem()
8691 if (Use_low_mem == 0) {