2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.14 2002/06/05 04:03:32 relnev
11 * finished cfilesystem.
13 * removed some old code.
15 * fixed mouse save off-by-one.
19 * Revision 1.13 2002/06/02 04:26:34 relnev
22 * Revision 1.12 2002/06/02 00:31:35 relnev
23 * implemented osregistry
25 * Revision 1.11 2002/06/01 09:00:34 relnev
26 * silly debug memmanager
28 * Revision 1.10 2002/06/01 07:12:32 relnev
29 * a few NDEBUG updates.
31 * removed a few warnings.
33 * Revision 1.9 2002/05/31 03:05:59 relnev
36 * Revision 1.8 2002/05/29 02:52:32 theoddone33
37 * Enable OpenGL renderer
39 * Revision 1.7 2002/05/28 08:52:03 relnev
40 * implemented two assembly stubs.
42 * cleaned up a few warnings.
44 * added a little demo hackery to make it progress a little farther.
46 * Revision 1.6 2002/05/28 06:28:20 theoddone33
47 * Filesystem mods, actually reads some data files now
49 * Revision 1.5 2002/05/28 04:07:28 theoddone33
50 * New graphics stubbing arrangement
52 * Revision 1.4 2002/05/27 22:46:52 theoddone33
53 * Remove more undefined symbols
55 * Revision 1.3 2002/05/26 23:31:18 relnev
56 * added a few files that needed to be compiled
58 * freespace.cpp: now compiles
60 * Revision 1.2 2002/05/07 03:16:44 theoddone33
61 * The Great Newline Fix
63 * Revision 1.1.1.1 2002/05/03 03:28:09 root
67 * 201 6/16/00 3:15p Jefff
68 * sim of the year dvd version changes, a few german soty localization
71 * 200 11/03/99 11:06a Jefff
74 * 199 10/26/99 5:07p Jamest
75 * fixed jeffs dumb debug code
77 * 198 10/25/99 5:53p Jefff
78 * call control_config_common_init() on startup
80 * 197 10/14/99 10:18a Daveb
81 * Fixed incorrect CD checking problem on standalone server.
83 * 196 10/13/99 9:22a Daveb
84 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
85 * related to movies. Fixed launcher spawning from PXO screen.
87 * 195 10/06/99 11:05a Jefff
88 * new oem upsell 3 hotspot coords
90 * 194 10/06/99 10:31a Jefff
93 * 193 10/01/99 9:10a Daveb
96 * 192 9/15/99 4:57a Dave
97 * Updated ships.tbl checksum
99 * 191 9/15/99 3:58a Dave
100 * Removed framerate warning at all times.
102 * 190 9/15/99 3:16a Dave
103 * Remove mt-011.fs2 from the builtin mission list.
105 * 189 9/15/99 1:45a Dave
106 * Don't init joystick on standalone. Fixed campaign mode on standalone.
107 * Fixed no-score-report problem in TvT
109 * 188 9/14/99 6:08a Dave
110 * Updated (final) single, multi, and campaign list.
112 * 187 9/14/99 3:26a Dave
113 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
114 * respawn-too-early problem. Made a few crash points safe.
116 * 186 9/13/99 4:52p Dave
119 * 185 9/12/99 8:09p Dave
120 * Fixed problem where skip-training button would cause mission messages
121 * not to get paged out for the current mission.
123 * 184 9/10/99 11:53a Dave
124 * Shutdown graphics before sound to eliminate apparent lockups when
125 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
127 * 183 9/09/99 11:40p Dave
128 * Handle an Assert() in beam code. Added supernova sounds. Play the right
129 * 2 end movies properly, based upon what the player did in the mission.
131 * 182 9/08/99 10:29p Dave
132 * Make beam sound pausing and unpausing much safer.
134 * 181 9/08/99 10:01p Dave
135 * Make sure game won't run in a drive's root directory. Make sure
136 * standalone routes suqad war messages properly to the host.
138 * 180 9/08/99 3:22p Dave
139 * Updated builtin mission list.
141 * 179 9/08/99 12:01p Jefff
142 * fixed Game_builtin_mission_list typo on Training-2.fs2
144 * 178 9/08/99 9:48a Andsager
145 * Add force feedback for engine wash.
147 * 177 9/07/99 4:01p Dave
148 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
149 * does everything properly (setting up address when binding). Remove
150 * black rectangle background from UI_INPUTBOX.
152 * 176 9/13/99 2:40a Dave
153 * Comment in full 80 minute CD check for RELEASE_REAL builds.
155 * 175 9/06/99 6:38p Dave
156 * Improved CD detection code.
158 * 174 9/06/99 1:30a Dave
159 * Intermediate checkin. Started on enforcing CD-in-drive to play the
162 * 173 9/06/99 1:16a Dave
163 * Make sure the user sees the intro movie.
165 * 172 9/04/99 8:00p Dave
166 * Fixed up 1024 and 32 bit movie support.
168 * 171 9/03/99 1:32a Dave
169 * CD checking by act. Added support to play 2 cutscenes in a row
170 * seamlessly. Fixed super low level cfile bug related to files in the
171 * root directory of a CD. Added cheat code to set campaign mission # in
174 * 170 9/01/99 10:49p Dave
175 * Added nice SquadWar checkbox to the client join wait screen.
177 * 169 9/01/99 10:14a Dave
180 * 168 8/29/99 4:51p Dave
181 * Fixed damaged checkin.
183 * 167 8/29/99 4:18p Andsager
184 * New "burst" limit for friendly damage. Also credit more damage done
185 * against large friendly ships.
187 * 166 8/27/99 6:38p Alanl
188 * crush the blasted repeating messages bug
190 * 164 8/26/99 9:09p Dave
191 * Force framerate check in everything but a RELEASE_REAL build.
193 * 163 8/26/99 9:45a Dave
194 * First pass at easter eggs and cheats.
196 * 162 8/24/99 8:55p Dave
197 * Make sure nondimming pixels work properly in tech menu.
199 * 161 8/24/99 1:49a Dave
200 * Fixed client-side afterburner stuttering. Added checkbox for no version
201 * checking on PXO join. Made button info passing more friendly between
204 * 160 8/22/99 5:53p Dave
205 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
206 * instead of ship designations for multiplayer players.
208 * 159 8/22/99 1:19p Dave
209 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
210 * which d3d cards are detected.
212 * 158 8/20/99 2:09p Dave
213 * PXO banner cycling.
215 * 157 8/19/99 10:59a Dave
216 * Packet loss detection.
218 * 156 8/19/99 10:12a Alanl
219 * preload mission-specific messages on machines greater than 48MB
221 * 155 8/16/99 4:04p Dave
222 * Big honking checkin.
224 * 154 8/11/99 5:54p Dave
225 * Fixed collision problem. Fixed standalone ghost problem.
227 * 153 8/10/99 7:59p Jefff
230 * 152 8/10/99 6:54p Dave
231 * Mad optimizations. Added paging to the nebula effect.
233 * 151 8/10/99 3:44p Jefff
234 * loads Intelligence information on startup
236 * 150 8/09/99 3:47p Dave
237 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
238 * non-nebula missions.
240 * 149 8/09/99 2:21p Andsager
241 * Fix patching from multiplayer direct to launcher update tab.
243 * 148 8/09/99 10:36a Dave
244 * Version info for game.
246 * 147 8/06/99 9:46p Dave
247 * Hopefully final changes for the demo.
249 * 146 8/06/99 3:34p Andsager
250 * Make title version info "(D)" -> "D" show up nicely
252 * 145 8/06/99 2:59p Adamp
253 * Fixed NT launcher/update problem.
255 * 144 8/06/99 1:52p Dave
256 * Bumped up MAX_BITMAPS for the demo.
258 * 143 8/06/99 12:17p Andsager
259 * Demo: down to just 1 demo dog
261 * 142 8/05/99 9:39p Dave
262 * Yet another new checksum.
264 * 141 8/05/99 6:19p Dave
265 * New demo checksums.
267 * 140 8/05/99 5:31p Andsager
268 * Up demo version 1.01
270 * 139 8/05/99 4:22p Andsager
271 * No time limit on upsell screens. Reverse order of display of upsell
274 * 138 8/05/99 4:17p Dave
275 * Tweaks to client interpolation.
277 * 137 8/05/99 3:52p Danw
279 * 136 8/05/99 3:01p Danw
281 * 135 8/05/99 2:43a Anoop
282 * removed duplicate definition.
284 * 134 8/05/99 2:13a Dave
287 * 133 8/05/99 2:05a Dave
290 * 132 8/05/99 1:22a Andsager
293 * 131 8/04/99 9:51p Andsager
294 * Add title screen to demo
296 * 130 8/04/99 6:47p Jefff
297 * fixed link error resulting from #ifdefs
299 * 129 8/04/99 6:26p Dave
300 * Updated ship tbl checksum.
302 * 128 8/04/99 5:40p Andsager
303 * Add multiple demo dogs
305 * 127 8/04/99 5:36p Andsager
306 * Show upsell screens at end of demo campaign before returning to main
309 * 126 8/04/99 11:42a Danw
310 * tone down EAX reverb
312 * 125 8/04/99 11:23a Dave
313 * Updated demo checksums.
315 * 124 8/03/99 11:02p Dave
316 * Maybe fixed sync problems in multiplayer.
318 * 123 8/03/99 6:21p Jefff
321 * 122 8/03/99 3:44p Andsager
322 * Launch laucher if trying to run FS without first having configured
325 * 121 8/03/99 12:45p Dave
328 * 120 8/02/99 9:13p Dave
331 * 119 7/30/99 10:31p Dave
332 * Added comm menu to the configurable hud files.
334 * 118 7/30/99 5:17p Andsager
335 * first fs2demo checksums
337 * 117 7/29/99 3:09p Anoop
339 * 116 7/29/99 12:05a Dave
340 * Nebula speed optimizations.
342 * 115 7/27/99 8:59a Andsager
343 * Make major, minor version consistent for all builds. Only show major
344 * and minor for launcher update window.
346 * 114 7/26/99 5:50p Dave
347 * Revised ingame join. Better? We'll see....
349 * 113 7/26/99 5:27p Andsager
350 * Add training mission as builtin to demo build
352 * 112 7/24/99 1:54p Dave
353 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
356 * 111 7/22/99 4:00p Dave
357 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
359 * 110 7/21/99 8:10p Dave
360 * First run of supernova effect.
362 * 109 7/20/99 1:49p Dave
363 * Peter Drake build. Fixed some release build warnings.
365 * 108 7/19/99 2:26p Andsager
366 * set demo multiplayer missions
368 * 107 7/18/99 5:19p Dave
369 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
371 * 106 7/16/99 1:50p Dave
372 * 8 bit aabitmaps. yay.
374 * 105 7/15/99 3:07p Dave
375 * 32 bit detection support. Mouse coord commandline.
377 * 104 7/15/99 2:13p Dave
378 * Added 32 bit detection.
380 * 103 7/15/99 9:20a Andsager
381 * FS2_DEMO initial checkin
383 * 102 7/14/99 11:02a Dave
384 * Skill level default back to easy. Blech.
386 * 101 7/09/99 5:54p Dave
387 * Seperated cruiser types into individual types. Added tons of new
388 * briefing icons. Campaign screen.
390 * 100 7/08/99 4:43p Andsager
391 * New check for sparky_hi and print if not found.
393 * 99 7/08/99 10:53a Dave
394 * New multiplayer interpolation scheme. Not 100% done yet, but still
395 * better than the old way.
397 * 98 7/06/99 4:24p Dave
398 * Mid-level checkin. Starting on some potentially cool multiplayer
401 * 97 7/06/99 3:35p Andsager
402 * Allow movie to play before red alert mission.
404 * 96 7/03/99 5:50p Dave
405 * Make rotated bitmaps draw properly in padlock views.
407 * 95 7/02/99 9:55p Dave
408 * Player engine wash sound.
410 * 94 7/02/99 4:30p Dave
411 * Much more sophisticated lightning support.
413 * 93 6/29/99 7:52p Dave
414 * Put in exception handling in FS2.
416 * 92 6/22/99 9:37p Dave
417 * Put in pof spewing.
419 * 91 6/16/99 4:06p Dave
420 * New pilot info popup. Added new draw-bitmap-as-poly function.
422 * 90 6/15/99 1:56p Andsager
423 * For release builds, allow start up in high res only with
426 * 89 6/15/99 9:34a Dave
427 * Fixed key checking in single threaded version of the stamp notification
430 * 88 6/09/99 2:55p Andsager
431 * Allow multiple asteroid subtypes (of large, medium, small) and follow
434 * 87 6/08/99 1:14a Dave
435 * Multi colored hud test.
437 * 86 6/04/99 9:52a Dave
438 * Fixed some rendering problems.
440 * 85 6/03/99 10:15p Dave
441 * Put in temporary main hall screen.
443 * 84 6/02/99 6:18p Dave
444 * Fixed TNT lockup problems! Wheeeee!
446 * 83 6/01/99 3:52p Dave
447 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
448 * dead popup, pxo find player popup, pxo private room popup.
450 * 82 5/26/99 1:28p Jasenw
451 * changed coords for loading ani
453 * 81 5/26/99 11:46a Dave
454 * Added ship-blasting lighting and made the randomization of lighting
455 * much more customizable.
457 * 80 5/24/99 5:45p Dave
458 * Added detail levels to the nebula, with a decent speedup. Split nebula
459 * lightning into its own section.
477 #include "systemvars.h"
482 #include "starfield.h"
483 #include "lighting.h"
488 #include "fireballs.h"
492 #include "floating.h"
493 #include "gamesequence.h"
495 #include "optionsmenu.h"
496 #include "playermenu.h"
497 #include "trainingmenu.h"
498 #include "techmenu.h"
501 #include "hudmessage.h"
503 #include "missiongoals.h"
504 #include "missionparse.h"
509 #include "multiutil.h"
510 #include "multimsgs.h"
514 #include "freespace.h"
515 #include "managepilot.h"
517 #include "contexthelp.h"
520 #include "missionbrief.h"
521 #include "missiondebrief.h"
523 #include "missionshipchoice.h"
525 #include "hudconfig.h"
526 #include "controlsconfig.h"
527 #include "missionmessage.h"
528 #include "missiontraining.h"
530 #include "hudtarget.h"
534 #include "eventmusic.h"
535 #include "animplay.h"
536 #include "missionweaponchoice.h"
537 #include "missionlog.h"
538 #include "audiostr.h"
540 #include "missioncampaign.h"
542 #include "missionhotkey.h"
543 #include "objectsnd.h"
544 #include "cmeasure.h"
546 #include "linklist.h"
547 #include "shockwave.h"
548 #include "afterburner.h"
553 #include "stand_gui.h"
554 #include "pcxutils.h"
555 #include "hudtargetbox.h"
556 #include "multi_xfer.h"
557 #include "hudescort.h"
558 #include "multiutil.h"
561 #include "multiteamselect.h"
564 #include "readyroom.h"
565 #include "mainhallmenu.h"
566 #include "multilag.h"
568 #include "particle.h"
570 #include "multi_ingame.h"
571 #include "snazzyui.h"
572 #include "asteroid.h"
573 #include "popupdead.h"
574 #include "multi_voice.h"
575 #include "missioncmdbrief.h"
576 #include "redalert.h"
577 #include "gameplayhelp.h"
578 #include "multilag.h"
579 #include "staticrand.h"
580 #include "multi_pmsg.h"
581 #include "levelpaging.h"
582 #include "observer.h"
583 #include "multi_pause.h"
584 #include "multi_endgame.h"
585 #include "cutscenes.h"
586 #include "multi_respawn.h"
587 // #include "movie.h"
588 #include "multi_obj.h"
589 #include "multi_log.h"
591 #include "localize.h"
592 #include "osregistry.h"
593 #include "barracks.h"
594 #include "missionpause.h"
596 #include "alphacolors.h"
597 #include "objcollide.h"
600 #include "neblightning.h"
601 #include "shipcontrails.h"
604 #include "multi_dogfight.h"
605 #include "multi_rate.h"
606 #include "muzzleflash.h"
610 #include "mainhalltemp.h"
611 #include "exceptionhandler.h"
615 #include "supernova.h"
616 #include "hudshield.h"
617 // #include "names.h"
619 #include "missionloopbrief.h"
623 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
629 // 1.00.04 5/26/98 MWA -- going final (12 pm)
630 // 1.00.03 5/26/98 MWA -- going final (3 am)
631 // 1.00.02 5/25/98 MWA -- going final
632 // 1.00.01 5/25/98 MWA -- going final
633 // 0.90 5/21/98 MWA -- getting ready for final.
634 // 0.10 4/9/98. Set by MK.
636 // Demo version: (obsolete since DEMO codebase split from tree)
637 // 0.03 4/10/98 AL. Interplay rev
638 // 0.02 4/8/98 MK. Increased when this system was modified.
639 // 0.01 4/7/98? AL. First release to Interplay QA.
642 // 1.00 5/28/98 AL. First release to Interplay QA.
644 void game_level_init(int seed = -1);
645 void game_post_level_init();
646 void game_do_frame();
647 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
648 void game_reset_time();
649 void game_show_framerate(); // draws framerate in lower right corner
651 int Game_no_clear = 0;
653 int Pofview_running = 0;
654 int Nebedit_running = 0;
656 typedef struct big_expl_flash {
657 float max_flash_intensity; // max intensity
658 float cur_flash_intensity; // cur intensity
659 int flash_start; // start time
662 #define FRAME_FILTER 16
664 #define DEFAULT_SKILL_LEVEL 1
665 int Game_skill_level = DEFAULT_SKILL_LEVEL;
667 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
668 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
670 #define EXE_FNAME ("fs2.exe")
671 #define LAUNCHER_FNAME ("freespace2.exe")
673 // JAS: Code for warphole camera.
674 // Needs to be cleaned up.
675 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
676 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
677 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
678 matrix Camera_orient = IDENTITY_MATRIX;
679 float Camera_damping = 1.0f;
680 float Camera_time = 0.0f;
681 float Warpout_time = 0.0f;
682 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
683 int Warpout_sound = -1;
685 int Use_joy_mouse = 0;
686 int Use_palette_flash = 1;
688 int Use_fullscreen_at_startup = 0;
690 int Show_area_effect = 0;
691 object *Last_view_target = NULL;
693 int dogfight_blown = 0;
696 float frametimes[FRAME_FILTER];
697 float frametotal = 0.0f;
701 int Show_framerate = 0;
703 int Show_framerate = 1;
706 int Framerate_cap = 120;
709 int Show_target_debug_info = 0;
710 int Show_target_weapons = 0;
714 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
717 int Debug_octant = -1;
719 fix Game_time_compression = F1_0;
721 // if the ships.tbl the player has is valid
722 int Game_ships_tbl_valid = 0;
724 // if the weapons.tbl the player has is valid
725 int Game_weapons_tbl_valid = 0;
729 extern int Player_attacking_enabled;
733 int Pre_player_entry;
735 int Fred_running = 0;
736 char Game_current_mission_filename[MAX_FILENAME_LEN];
737 int game_single_step = 0;
738 int last_single_step=0;
740 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
741 extern int MSG_WINDOW_Y_START;
742 extern int MSG_WINDOW_HEIGHT;
744 int game_zbuffer = 1;
745 //static int Game_music_paused;
746 static int Game_paused;
750 #define EXPIRE_BAD_CHECKSUM 1
751 #define EXPIRE_BAD_TIME 2
753 extern void ssm_init();
754 extern void ssm_level_init();
755 extern void ssm_process();
757 // static variable to contain the time this version was built
758 // commented out for now until
759 // I figure out how to get the username into the file
760 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
762 // defines and variables used for dumping frame for making trailers.
764 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
765 int Debug_dump_trigger = 0;
766 int Debug_dump_frame_count;
767 int Debug_dump_frame_num = 0;
768 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
771 // amount of time to wait after the player has died before we display the death died popup
772 #define PLAYER_DIED_POPUP_WAIT 2500
773 int Player_died_popup_wait = -1;
774 int Player_multi_died_check = -1;
776 // builtin mission list stuff
778 int Game_builtin_mission_count = 6;
779 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
780 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
781 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
782 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
783 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
784 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
785 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
787 #elif defined(PD_BUILD)
788 int Game_builtin_mission_count = 4;
789 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
790 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
791 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
792 { "sm1-01", (FSB_FROM_VOLITION), "" },
793 { "sm1-05", (FSB_FROM_VOLITION), "" },
795 #elif defined(MULTIPLAYER_BETA)
796 int Game_builtin_mission_count = 17;
797 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
799 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
800 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
801 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
802 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
803 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
804 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
805 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
806 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
807 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
808 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
809 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
810 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
811 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
812 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
813 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
814 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
815 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
817 #elif defined(OEM_BUILD)
818 int Game_builtin_mission_count = 17;
819 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
820 // oem version - act 1 only
821 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
824 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
825 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
826 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
827 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
828 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
829 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
830 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
831 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
832 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
833 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
834 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
835 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
836 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
837 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
838 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
839 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
842 int Game_builtin_mission_count = 92;
843 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
844 // single player campaign
845 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
848 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
849 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
850 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
851 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
852 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
853 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
854 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
855 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
856 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
857 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
858 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
859 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
860 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
861 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
862 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
863 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
864 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
865 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
866 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
869 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
870 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
871 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
872 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
873 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
874 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
875 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
876 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
877 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
878 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
881 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
882 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
883 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
884 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
885 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
886 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
887 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
888 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
889 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
890 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
891 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
892 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
894 // multiplayer missions
897 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
922 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
927 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
933 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
939 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
951 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
952 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
953 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
954 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
959 // Internal function prototypes
960 void game_maybe_draw_mouse(float frametime);
961 void init_animating_pointer();
962 void load_animating_pointer(char *filename, int dx, int dy);
963 void unload_animating_pointer();
964 void game_do_training_checks();
965 void game_shutdown(void);
966 void game_show_event_debug(float frametime);
967 void game_event_debug_init();
969 void demo_upsell_show_screens();
970 void game_start_subspace_ambient_sound();
971 void game_stop_subspace_ambient_sound();
972 void verify_ships_tbl();
973 void verify_weapons_tbl();
974 void display_title_screen();
976 // loading background filenames
977 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
978 "LoadingBG", // GR_640
979 "2_LoadingBG" // GR_1024
983 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
984 "Loading.ani", // GR_640
985 "2_Loading.ani" // GR_1024
988 #if defined(FS2_DEMO)
989 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
993 #elif defined(OEM_BUILD)
994 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1001 char Game_CDROM_dir[MAX_PATH_LEN];
1004 // How much RAM is on this machine. Set in WinMain
1005 uint Freespace_total_ram = 0;
1008 float Game_flash_red = 0.0f;
1009 float Game_flash_green = 0.0f;
1010 float Game_flash_blue = 0.0f;
1011 float Sun_spot = 0.0f;
1012 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1014 // game shudder stuff (in ms)
1015 int Game_shudder_time = -1;
1016 int Game_shudder_total = 0;
1017 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1020 sound_env Game_sound_env;
1021 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1022 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1024 int Game_sound_env_update_timestamp;
1026 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1029 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1031 fs_builtin_mission *game_find_builtin_mission(char *filename)
1035 // look through all existing builtin missions
1036 for(idx=0; idx<Game_builtin_mission_count; idx++){
1037 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1038 return &Game_builtin_mission_list[idx];
1046 int game_get_default_skill_level()
1048 return DEFAULT_SKILL_LEVEL;
1052 void game_flash_reset()
1054 Game_flash_red = 0.0f;
1055 Game_flash_green = 0.0f;
1056 Game_flash_blue = 0.0f;
1058 Big_expl_flash.max_flash_intensity = 0.0f;
1059 Big_expl_flash.cur_flash_intensity = 0.0f;
1060 Big_expl_flash.flash_start = 0;
1063 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1064 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1066 void game_framerate_check_init()
1068 // zero critical time
1069 Gf_critical_time = 0.0f;
1072 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1073 // if this is a glide card
1074 if(gr_screen.mode == GR_GLIDE){
1076 extern GrHwConfiguration hwconfig;
1079 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1080 Gf_critical = 15.0f;
1084 Gf_critical = 10.0f;
1089 Gf_critical = 15.0f;
1092 // d3d. only care about good cards here I guess (TNT)
1094 Gf_critical = 15.0f;
1097 // if this is a glide card
1098 if(gr_screen.mode == GR_GLIDE){
1100 extern GrHwConfiguration hwconfig;
1103 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1104 Gf_critical = 25.0f;
1108 Gf_critical = 20.0f;
1113 Gf_critical = 25.0f;
1116 // d3d. only care about good cards here I guess (TNT)
1118 Gf_critical = 25.0f;
1123 extern float Framerate;
1124 void game_framerate_check()
1128 // if the current framerate is above the critical level, add frametime
1129 if(Framerate >= Gf_critical){
1130 Gf_critical_time += flFrametime;
1133 if(!Show_framerate){
1137 // display if we're above the critical framerate
1138 if(Framerate < Gf_critical){
1139 gr_set_color_fast(&Color_bright_red);
1140 gr_string(200, y_start, "Framerate warning");
1145 // display our current pct of good frametime
1146 if(f2fl(Missiontime) >= 0.0f){
1147 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1150 gr_set_color_fast(&Color_bright_green);
1152 gr_set_color_fast(&Color_bright_red);
1155 gr_printf(200, y_start, "%d%%", (int)pct);
1162 // Adds a flash effect. These can be positive or negative.
1163 // The range will get capped at around -1 to 1, so stick
1164 // with a range like that.
1165 void game_flash( float r, float g, float b )
1167 Game_flash_red += r;
1168 Game_flash_green += g;
1169 Game_flash_blue += b;
1171 if ( Game_flash_red < -1.0f ) {
1172 Game_flash_red = -1.0f;
1173 } else if ( Game_flash_red > 1.0f ) {
1174 Game_flash_red = 1.0f;
1177 if ( Game_flash_green < -1.0f ) {
1178 Game_flash_green = -1.0f;
1179 } else if ( Game_flash_green > 1.0f ) {
1180 Game_flash_green = 1.0f;
1183 if ( Game_flash_blue < -1.0f ) {
1184 Game_flash_blue = -1.0f;
1185 } else if ( Game_flash_blue > 1.0f ) {
1186 Game_flash_blue = 1.0f;
1191 // Adds a flash for Big Ship explosions
1192 // cap range from 0 to 1
1193 void big_explosion_flash(float flash)
1195 Big_expl_flash.flash_start = timestamp(1);
1199 } else if (flash < 0.0f) {
1203 Big_expl_flash.max_flash_intensity = flash;
1204 Big_expl_flash.cur_flash_intensity = 0.0f;
1207 // Amount to diminish palette towards normal, per second.
1208 #define DIMINISH_RATE 0.75f
1209 #define SUN_DIMINISH_RATE 6.00f
1213 float sn_glare_scale = 1.7f;
1216 dc_get_arg(ARG_FLOAT);
1217 sn_glare_scale = Dc_arg_float;
1220 float Supernova_last_glare = 0.0f;
1221 void game_sunspot_process(float frametime)
1225 float Sun_spot_goal = 0.0f;
1228 sn_stage = supernova_active();
1230 // sunspot differently based on supernova stage
1232 // approaching. player still in control
1235 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1238 light_get_global_dir(&light_dir, 0);
1240 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1243 // scale it some more
1244 dot = dot * (0.5f + (pct * 0.5f));
1247 Sun_spot_goal += (dot * sn_glare_scale);
1250 // draw the sun glow
1251 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1252 // draw the glow for this sun
1253 stars_draw_sun_glow(0);
1256 Supernova_last_glare = Sun_spot_goal;
1259 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1262 Sun_spot_goal = 0.9f;
1263 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1265 if(Sun_spot_goal > 1.0f){
1266 Sun_spot_goal = 1.0f;
1269 Sun_spot_goal *= sn_glare_scale;
1270 Supernova_last_glare = Sun_spot_goal;
1273 // fade to white. display dead popup
1276 Supernova_last_glare += (2.0f * flFrametime);
1277 if(Supernova_last_glare > 2.0f){
1278 Supernova_last_glare = 2.0f;
1281 Sun_spot_goal = Supernova_last_glare;
1288 // check sunspots for all suns
1289 n_lights = light_get_global_count();
1292 for(idx=0; idx<n_lights; idx++){
1293 //(vector *eye_pos, matrix *eye_orient)
1294 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1297 light_get_global_dir(&light_dir, idx);
1299 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1301 Sun_spot_goal += (float)pow(dot,85.0f);
1303 // draw the glow for this sun
1304 stars_draw_sun_glow(idx);
1306 Sun_spot_goal = 0.0f;
1312 Sun_spot_goal = 0.0f;
1316 float dec_amount = frametime*SUN_DIMINISH_RATE;
1318 if ( Sun_spot < Sun_spot_goal ) {
1319 Sun_spot += dec_amount;
1320 if ( Sun_spot > Sun_spot_goal ) {
1321 Sun_spot = Sun_spot_goal;
1323 } else if ( Sun_spot > Sun_spot_goal ) {
1324 Sun_spot -= dec_amount;
1325 if ( Sun_spot < Sun_spot_goal ) {
1326 Sun_spot = Sun_spot_goal;
1332 // Call once a frame to diminish the
1333 // flash effect to 0.
1334 void game_flash_diminish(float frametime)
1336 float dec_amount = frametime*DIMINISH_RATE;
1338 if ( Game_flash_red > 0.0f ) {
1339 Game_flash_red -= dec_amount;
1340 if ( Game_flash_red < 0.0f )
1341 Game_flash_red = 0.0f;
1343 Game_flash_red += dec_amount;
1344 if ( Game_flash_red > 0.0f )
1345 Game_flash_red = 0.0f;
1348 if ( Game_flash_green > 0.0f ) {
1349 Game_flash_green -= dec_amount;
1350 if ( Game_flash_green < 0.0f )
1351 Game_flash_green = 0.0f;
1353 Game_flash_green += dec_amount;
1354 if ( Game_flash_green > 0.0f )
1355 Game_flash_green = 0.0f;
1358 if ( Game_flash_blue > 0.0f ) {
1359 Game_flash_blue -= dec_amount;
1360 if ( Game_flash_blue < 0.0f )
1361 Game_flash_blue = 0.0f;
1363 Game_flash_blue += dec_amount;
1364 if ( Game_flash_blue > 0.0f )
1365 Game_flash_blue = 0.0f;
1368 // update big_explosion_cur_flash
1369 #define TIME_UP 1500
1370 #define TIME_DOWN 2500
1371 int duration = TIME_UP + TIME_DOWN;
1372 int time = timestamp_until(Big_expl_flash.flash_start);
1373 if (time > -duration) {
1375 if (time < TIME_UP) {
1376 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1379 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1383 if ( Use_palette_flash ) {
1385 // static int or=0, og=0, ob=0;
1387 // Change the 200 to change the color range of colors.
1388 r = fl2i( Game_flash_red*128.0f );
1389 g = fl2i( Game_flash_green*128.0f );
1390 b = fl2i( Game_flash_blue*128.0f );
1392 if ( Sun_spot > 0.0f ) {
1393 r += fl2i(Sun_spot*128.0f);
1394 g += fl2i(Sun_spot*128.0f);
1395 b += fl2i(Sun_spot*128.0f);
1398 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1399 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1400 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1401 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1404 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1405 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1406 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1408 if ( (r!=0) || (g!=0) || (b!=0) ) {
1409 gr_flash( r, g, b );
1411 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1422 void game_level_close()
1424 // De-Initialize the game subsystems
1425 message_mission_shutdown();
1426 event_music_level_close();
1427 game_stop_looped_sounds();
1429 obj_snd_level_close(); // uninit object-linked persistant sounds
1430 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1431 anim_level_close(); // stop and clean up any anim instances
1432 shockwave_level_close();
1433 fireball_level_close();
1435 mission_event_shutdown();
1436 asteroid_level_close();
1437 model_cache_reset(); // Reset/free all the model caching stuff
1438 flak_level_close(); // unload flak stuff
1439 neb2_level_close(); // shutdown gaseous nebula stuff
1442 mflash_level_close();
1444 audiostream_unpause_all();
1449 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1450 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1451 void game_level_init(int seed)
1453 // seed the random number generator
1455 // if no seed was passed, seed the generator either from the time value, or from the
1456 // netgame security flags -- ensures that all players in multiplayer game will have the
1457 // same randon number sequence (with static rand functions)
1458 if ( Game_mode & GM_NORMAL ) {
1459 Game_level_seed = time(NULL);
1461 Game_level_seed = Netgame.security;
1464 // mwa 9/17/98 -- maybe this assert isn't needed????
1465 Assert( !(Game_mode & GM_MULTIPLAYER) );
1466 Game_level_seed = seed;
1468 srand( Game_level_seed );
1470 // semirand function needs to get re-initted every time in multiplayer
1471 if ( Game_mode & GM_MULTIPLAYER ){
1477 Key_normal_game = (Game_mode & GM_NORMAL);
1480 Game_shudder_time = -1;
1482 // Initialize the game subsystems
1483 // timestamp_reset(); // Must be inited before everything else
1485 game_reset_time(); // resets time, and resets saved time too
1487 obj_init(); // Must be inited before the other systems
1488 model_free_all(); // Free all existing models
1489 mission_brief_common_init(); // Free all existing briefing/debriefing text
1490 weapon_level_init();
1491 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1493 player_level_init();
1494 shipfx_flash_init(); // Init the ship gun flash system.
1495 game_flash_reset(); // Reset the flash effect
1496 particle_init(); // Reset the particle system
1500 shield_hit_init(); // Initialize system for showing shield hits
1501 radar_mission_init();
1502 mission_init_goals();
1505 obj_snd_level_init(); // init object-linked persistant sounds
1507 shockwave_level_init();
1508 afterburner_level_init();
1509 scoring_level_init( &Player->stats );
1511 asteroid_level_init();
1512 control_config_clear_used_status();
1513 collide_ship_ship_sounds_init();
1515 Pre_player_entry = 1; // Means the player has not yet entered.
1516 Entry_delay_time = 0; // Could get overwritten in mission read.
1517 fireball_preload(); // page in warphole bitmaps
1519 flak_level_init(); // initialize flak - bitmaps, etc
1520 ct_level_init(); // initialize ships contrails, etc
1521 awacs_level_init(); // initialize AWACS
1522 beam_level_init(); // initialize beam weapons
1523 mflash_level_init();
1525 supernova_level_init();
1527 // multiplayer dogfight hack
1530 shipfx_engine_wash_level_init();
1534 Last_view_target = NULL;
1539 // campaign wasn't ended
1540 Campaign_ended_in_mission = 0;
1543 // called when a mission is over -- does server specific stuff.
1544 void freespace_stop_mission()
1547 Game_mode &= ~GM_IN_MISSION;
1550 // called at frame interval to process networking stuff
1551 void game_do_networking()
1553 Assert( Net_player != NULL );
1554 if (!(Game_mode & GM_MULTIPLAYER)){
1558 // see if this player should be reading/writing data. Bit is set when at join
1559 // screen onward until quits back to main menu.
1560 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1564 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1567 multi_pause_do_frame();
1572 // Loads the best palette for this level, based
1573 // on nebula color and hud color. You could just call palette_load_table with
1574 // the appropriate filename, but who wants to do that.
1575 void game_load_palette()
1577 char palette_filename[1024];
1579 // We only use 3 hud colors right now
1580 // Assert( HUD_config.color >= 0 );
1581 // Assert( HUD_config.color <= 2 );
1583 Assert( Mission_palette >= 0 );
1584 Assert( Mission_palette <= 98 );
1586 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1587 strcpy( palette_filename, NOX("gamepalette-subspace") );
1589 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1592 mprintf(( "Loading palette %s\n", palette_filename ));
1594 // palette_load_table(palette_filename);
1597 void game_post_level_init()
1599 // Stuff which gets called after mission is loaded. Because player isn't created until
1600 // after mission loads, some things must get initted after the level loads
1602 model_level_post_init();
1605 hud_setup_escort_list();
1606 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1612 game_event_debug_init();
1615 training_mission_init();
1616 asteroid_create_all();
1618 game_framerate_check_init();
1622 // An estimate as to how high the count passed to game_loading_callback will go.
1623 // This is just a guess, it seems to always be about the same. The count is
1624 // proportional to the code being executed, not the time, so this works good
1625 // for a bar, assuming the code does about the same thing each time you
1626 // load a level. You can find this value by looking at the return value
1627 // of game_busy_callback(NULL), which I conveniently print out to the
1628 // debug output window with the '=== ENDING LOAD ==' stuff.
1629 //#define COUNT_ESTIMATE 3706
1630 #define COUNT_ESTIMATE 1111
1632 int Game_loading_callback_inited = 0;
1634 int Game_loading_background = -1;
1635 anim * Game_loading_ani = NULL;
1636 anim_instance *Game_loading_ani_instance;
1637 int Game_loading_frame=-1;
1639 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1648 // This gets called 10x per second and count is the number of times
1649 // game_busy() has been called since the current callback function
1651 void game_loading_callback(int count)
1653 game_do_networking();
1655 Assert( Game_loading_callback_inited==1 );
1656 Assert( Game_loading_ani != NULL );
1658 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1659 if ( framenum > Game_loading_ani->total_frames-1 ) {
1660 framenum = Game_loading_ani->total_frames-1;
1661 } else if ( framenum < 0 ) {
1666 while ( Game_loading_frame < framenum ) {
1667 Game_loading_frame++;
1668 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1672 if ( cbitmap > -1 ) {
1673 if ( Game_loading_background > -1 ) {
1674 gr_set_bitmap( Game_loading_background );
1678 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1679 gr_set_bitmap( cbitmap );
1680 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1682 bm_release(cbitmap);
1688 void game_loading_callback_init()
1690 Assert( Game_loading_callback_inited==0 );
1692 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1693 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1696 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1697 Assert( Game_loading_ani != NULL );
1698 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1699 Assert( Game_loading_ani_instance != NULL );
1700 Game_loading_frame = -1;
1702 Game_loading_callback_inited = 1;
1704 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1709 void game_loading_callback_close()
1711 Assert( Game_loading_callback_inited==1 );
1713 // Make sure bar shows all the way over.
1714 game_loading_callback(COUNT_ESTIMATE);
1716 int real_count = game_busy_callback( NULL );
1719 Game_loading_callback_inited = 0;
1722 mprintf(( "=================== ENDING LOAD ================\n" ));
1723 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1724 mprintf(( "================================================\n" ));
1726 // to remove warnings in release build
1730 free_anim_instance(Game_loading_ani_instance);
1731 Game_loading_ani_instance = NULL;
1732 anim_free(Game_loading_ani);
1733 Game_loading_ani = NULL;
1735 bm_release( Game_loading_background );
1736 common_free_interface_palette(); // restore game palette
1737 Game_loading_background = -1;
1739 gr_set_font( FONT1 );
1742 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1744 void game_maybe_update_sound_environment()
1746 // do nothing for now
1749 // Assign the sound environment for the game, based on the current mission
1751 void game_assign_sound_environment()
1754 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1755 Game_sound_env.id = SND_ENV_DRUGGED;
1756 Game_sound_env.volume = 0.800f;
1757 Game_sound_env.damping = 1.188f;
1758 Game_sound_env.decay = 6.392f;
1760 } else if (Num_asteroids > 30) {
1761 Game_sound_env.id = SND_ENV_AUDITORIUM;
1762 Game_sound_env.volume = 0.603f;
1763 Game_sound_env.damping = 0.5f;
1764 Game_sound_env.decay = 4.279f;
1767 Game_sound_env = Game_default_sound_env;
1771 Game_sound_env = Game_default_sound_env;
1772 Game_sound_env_update_timestamp = timestamp(1);
1775 // function which gets called before actually entering the mission. It is broken down into a funciton
1776 // since it will get called in one place from a single player game and from another place for
1777 // a multiplayer game
1778 void freespace_mission_load_stuff()
1780 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1781 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1782 if(!(Game_mode & GM_STANDALONE_SERVER)){
1784 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1786 game_loading_callback_init();
1788 event_music_level_init(); // preloads the first 2 seconds for each event music track
1791 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1794 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1797 ship_assign_sound_all(); // assign engine sounds to ships
1798 game_assign_sound_environment(); // assign the sound environment for this mission
1801 // call function in missionparse.cpp to fixup player/ai stuff.
1802 mission_parse_fixup_players();
1805 // Load in all the bitmaps for this level
1810 game_loading_callback_close();
1812 // the only thing we need to call on the standalone for now.
1814 // call function in missionparse.cpp to fixup player/ai stuff.
1815 mission_parse_fixup_players();
1817 // Load in all the bitmaps for this level
1823 uint load_mission_load;
1824 uint load_post_level_init;
1825 uint load_mission_stuff;
1827 // tells the server to load the mission and initialize structures
1828 int game_start_mission()
1830 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1832 load_gl_init = time(NULL);
1834 load_gl_init = time(NULL) - load_gl_init;
1836 if (Game_mode & GM_MULTIPLAYER) {
1837 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1839 // clear multiplayer stats
1840 init_multiplayer_stats();
1843 load_mission_load = time(NULL);
1844 if (mission_load()) {
1845 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1846 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1847 gameseq_post_event(GS_EVENT_MAIN_MENU);
1849 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1854 load_mission_load = time(NULL) - load_mission_load;
1856 // If this is a red alert mission in campaign mode, bash wingman status
1857 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1858 red_alert_bash_wingman_status();
1861 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1862 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1863 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1864 // game_load_palette();
1867 load_post_level_init = time(NULL);
1868 game_post_level_init();
1869 load_post_level_init = time(NULL) - load_post_level_init;
1873 void Do_model_timings_test();
1874 Do_model_timings_test();
1878 load_mission_stuff = time(NULL);
1879 freespace_mission_load_stuff();
1880 load_mission_stuff = time(NULL) - load_mission_stuff;
1885 int Interface_framerate = 0;
1888 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1889 DCF_BOOL( show_framerate, Show_framerate )
1890 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1891 DCF_BOOL( show_target_weapons, Show_target_weapons )
1892 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1893 DCF_BOOL( sound, Sound_enabled )
1894 DCF_BOOL( zbuffer, game_zbuffer )
1895 DCF_BOOL( shield_system, New_shield_system )
1896 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1897 DCF_BOOL( player_attacking, Player_attacking_enabled )
1898 DCF_BOOL( show_waypoints, Show_waypoints )
1899 DCF_BOOL( show_area_effect, Show_area_effect )
1900 DCF_BOOL( show_net_stats, Show_net_stats )
1901 DCF_BOOL( log, Log_debug_output_to_file )
1902 DCF_BOOL( training_msg_method, Training_msg_method )
1903 DCF_BOOL( show_player_pos, Show_player_pos )
1904 DCF_BOOL(i_framerate, Interface_framerate )
1906 DCF(show_mem,"Toggles showing mem usage")
1909 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1910 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1911 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1912 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1918 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1920 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1921 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1925 DCF(show_cpu,"Toggles showing cpu usage")
1928 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1929 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1930 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1931 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1937 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1939 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1940 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1947 // AL 4-8-98: always allow players to display their framerate
1950 DCF_BOOL( show_framerate, Show_framerate )
1957 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1960 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1961 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1962 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1963 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1965 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" );
1966 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1968 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1971 DCF(palette_flash,"Toggles palette flash effect on/off")
1974 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1975 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1976 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1977 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1979 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1980 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1983 int Use_low_mem = 0;
1985 DCF(low_mem,"Uses low memory settings regardless of RAM")
1988 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1989 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1990 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1991 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1993 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1994 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1996 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2002 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2005 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2006 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2007 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2008 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2010 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2011 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2012 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2016 int Framerate_delay = 0;
2018 float Freespace_gamma = 1.0f;
2020 DCF(gamma,"Sets Gamma factor")
2023 dc_get_arg(ARG_FLOAT|ARG_NONE);
2024 if ( Dc_arg_type & ARG_FLOAT ) {
2025 Freespace_gamma = Dc_arg_float;
2027 dc_printf( "Gamma reset to 1.0f\n" );
2028 Freespace_gamma = 1.0f;
2030 if ( Freespace_gamma < 0.1f ) {
2031 Freespace_gamma = 0.1f;
2032 } else if ( Freespace_gamma > 5.0f ) {
2033 Freespace_gamma = 5.0f;
2035 gr_set_gamma(Freespace_gamma);
2037 char tmp_gamma_string[32];
2038 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2039 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2043 dc_printf( "Usage: gamma <float>\n" );
2044 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2045 Dc_status = 0; // don't print status if help is printed. Too messy.
2049 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2058 Game_current_mission_filename[0] = 0;
2060 // seed the random number generator
2061 Game_init_seed = time(NULL);
2062 srand( Game_init_seed );
2064 Framerate_delay = 0;
2070 extern void bm_init();
2076 // Initialize the timer before the os
2084 GetCurrentDirectory(1024, whee);
2087 getcwd (whee, 1024);
2090 strcat(whee, EXE_FNAME);
2092 //Initialize the libraries
2093 s1 = timer_get_milliseconds();
2094 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2097 e1 = timer_get_milliseconds();
2099 // time a bunch of cfopens
2101 s2 = timer_get_milliseconds();
2103 for(int idx=0; idx<10000; idx++){
2104 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2109 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2111 e2 = timer_get_milliseconds();
2114 if (Is_standalone) {
2115 std_init_standalone();
2117 os_init( Osreg_class_name, Osreg_app_name );
2118 os_set_title(Osreg_title);
2121 // initialize localization module. Make sure this is down AFTER initialzing OS.
2122 // int t1 = timer_get_milliseconds();
2125 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2127 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2130 // verify that he has a valid weapons.tbl
2131 verify_weapons_tbl();
2133 // Output version numbers to registry for auto patching purposes
2134 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2135 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2136 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2138 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2139 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2140 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2143 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2147 Asteroids_enabled = 1;
2150 /////////////////////////////
2152 /////////////////////////////
2157 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2158 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2160 if (!stricmp(ptr, NOX("no sound"))) {
2161 Cmdline_freespace_no_sound = 1;
2163 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2165 } else if (!stricmp(ptr, NOX("EAX"))) {
2170 if (!Is_standalone) {
2171 snd_init(use_a3d, use_eax);
2173 /////////////////////////////
2175 /////////////////////////////
2177 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2180 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);
2182 // fire up the UpdateLauncher executable
2184 PROCESS_INFORMATION pi;
2186 memset( &si, 0, sizeof(STARTUPINFO) );
2189 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2190 NULL, // pointer to command line string
2191 NULL, // pointer to process security attributes
2192 NULL, // pointer to thread security attributes
2193 FALSE, // handle inheritance flag
2194 CREATE_DEFAULT_ERROR_MODE, // creation flags
2195 NULL, // pointer to new environment block
2196 NULL, // pointer to current directory name
2197 &si, // pointer to STARTUPINFO
2198 &pi // pointer to PROCESS_INFORMATION
2201 // If the Launcher could not be started up, let the user know
2203 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2212 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2214 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);
2222 // check for hi res pack file
2223 int has_sparky_hi = 0;
2225 // check if sparky_hi exists -- access mode 0 means does file exist
2228 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2231 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2234 // see if we've got 32 bit in the string
2235 if(strstr(ptr, "32 bit")){
2242 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2244 // always 640 for E3
2245 gr_init(GR_640, GR_GLIDE);
2247 // regular or hi-res ?
2249 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2251 if(strstr(ptr, NOX("(1024x768)"))){
2253 gr_init(GR_1024, GR_GLIDE);
2255 gr_init(GR_640, GR_GLIDE);
2258 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2260 // always 640 for E3
2262 gr_init(GR_640, GR_DIRECT3D, depth);
2264 // regular or hi-res ?
2266 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2268 if(strstr(ptr, NOX("(1024x768)"))){
2272 gr_init(GR_1024, GR_DIRECT3D, depth);
2276 gr_init(GR_640, GR_DIRECT3D, depth);
2282 if ( Use_fullscreen_at_startup && !Is_standalone) {
2283 gr_init(GR_640, GR_DIRECTDRAW);
2285 gr_init(GR_640, GR_SOFTWARE);
2288 if ( !Is_standalone ) {
2289 gr_init(GR_640, GR_DIRECTDRAW);
2291 gr_init(GR_640, GR_SOFTWARE);
2296 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2297 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2298 gr_init(GR_1024, GR_OPENGL);
2300 gr_init(GR_640, GR_OPENGL);
2304 gr_init(GR_640, GR_SOFTWARE);
2309 extern int Gr_inited;
2310 if(trying_d3d && !Gr_inited){
2312 extern char Device_init_error[512];
2313 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2322 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2323 Freespace_gamma = (float)atof(ptr);
2324 if ( Freespace_gamma == 0.0f ) {
2325 Freespace_gamma = 1.80f;
2326 } else if ( Freespace_gamma < 0.1f ) {
2327 Freespace_gamma = 0.1f;
2328 } else if ( Freespace_gamma > 5.0f ) {
2329 Freespace_gamma = 5.0f;
2331 char tmp_gamma_string[32];
2332 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2333 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2335 gr_set_gamma(Freespace_gamma);
2337 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2340 display_title_screen();
2344 // attempt to load up master tracker registry info (login and password)
2345 Multi_tracker_id = -1;
2347 // pxo login and password
2348 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2350 nprintf(("Network","Error reading in PXO login data\n"));
2351 strcpy(Multi_tracker_login,"");
2353 strcpy(Multi_tracker_login,ptr);
2355 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2357 nprintf(("Network","Error reading PXO password\n"));
2358 strcpy(Multi_tracker_passwd,"");
2360 strcpy(Multi_tracker_passwd,ptr);
2363 // pxo squad name and password
2364 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2366 nprintf(("Network","Error reading in PXO squad name\n"));
2367 strcpy(Multi_tracker_squad_name, "");
2369 strcpy(Multi_tracker_squad_name, ptr);
2372 // If less than 48MB of RAM, use low memory model.
2373 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2374 mprintf(( "Using normal memory settings...\n" ));
2375 bm_set_low_mem(1); // Use every other frame of bitmaps
2377 mprintf(( "Using high memory settings...\n" ));
2378 bm_set_low_mem(0); // Use all frames of bitmaps
2381 // load non-darkening pixel defs
2382 palman_load_pixels();
2384 // hud shield icon stuff
2385 hud_shield_game_init();
2387 control_config_common_init(); // sets up localization stuff in the control config
2393 gamesnd_parse_soundstbl();
2398 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2403 player_controls_init();
2406 //if(!Is_standalone){
2414 ship_init(); // read in ships.tbl
2416 mission_campaign_init(); // load in the default campaign
2418 // navmap_init(); // init the navigation map system
2419 context_help_init();
2420 techroom_intel_init(); // parse species.tbl, load intel info
2422 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2423 init_animating_pointer();
2425 mission_brief_common_init(); // Mark all the briefing structures as empty.
2426 gr_font_init(); // loads up all fonts
2428 neb2_init(); // fullneb stuff
2432 player_tips_init(); // helpful tips
2435 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2436 pilot_load_pic_list();
2437 pilot_load_squad_pic_list();
2439 load_animating_pointer(NOX("cursor"), 0, 0);
2441 // initialize alpha colors
2442 alpha_colors_init();
2445 // Game_music_paused = 0;
2452 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2453 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2455 mprintf(("cfile_init() took %d\n", e1 - s1));
2456 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2459 char transfer_text[128];
2461 float Start_time = 0.0f;
2463 float Framerate = 0.0f;
2465 float Timing_total = 0.0f;
2466 float Timing_render2 = 0.0f;
2467 float Timing_render3 = 0.0f;
2468 float Timing_flip = 0.0f;
2469 float Timing_clear = 0.0f;
2471 MONITOR(NumPolysDrawn);
2477 void game_get_framerate()
2479 char text[128] = "";
2481 if ( frame_int == -1 ) {
2483 for (i=0; i<FRAME_FILTER; i++ ) {
2484 frametimes[i] = 0.0f;
2489 frametotal -= frametimes[frame_int];
2490 frametotal += flFrametime;
2491 frametimes[frame_int] = flFrametime;
2492 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2494 if ( frametotal != 0.0 ) {
2495 if ( Framecount >= FRAME_FILTER )
2496 Framerate = FRAME_FILTER / frametotal;
2498 Framerate = Framecount / frametotal;
2499 sprintf( text, NOX("FPS: %.1f"), Framerate );
2501 sprintf( text, NOX("FPS: ?") );
2505 if (Show_framerate) {
2506 gr_set_color_fast(&HUD_color_debug);
2507 gr_string( 570, 2, text );
2511 void game_show_framerate()
2515 cur_time = f2fl(timer_get_approx_seconds());
2516 if (cur_time - Start_time > 30.0f) {
2517 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2518 Start_time += 1000.0f;
2521 //mprintf(( "%s\n", text ));
2524 if ( Debug_dump_frames )
2528 // possibly show control checking info
2529 control_check_indicate();
2531 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2532 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2533 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2534 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2537 if ( Show_cpu == 1 ) {
2542 dy = gr_get_font_height() + 1;
2544 gr_set_color_fast(&HUD_color_debug);
2548 extern int D3D_textures_in;
2549 extern int D3D_textures_in_frame;
2550 extern int Glide_textures_in;
2551 extern int Glide_textures_in_frame;
2552 extern int Glide_explosion_vram;
2553 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2555 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2557 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2563 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2565 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2567 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2569 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2571 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2576 extern int Num_pairs; // Number of object pairs that were checked.
2577 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2580 extern int Num_pairs_checked; // What percent of object pairs were checked.
2581 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2583 Num_pairs_checked = 0;
2587 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2590 if ( Timing_total > 0.01f ) {
2591 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2593 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2595 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2597 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2599 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2609 dy = gr_get_font_height() + 1;
2611 gr_set_color_fast(&HUD_color_debug);
2614 extern int TotalRam;
2615 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2620 extern int Model_ram;
2621 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2625 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2627 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2629 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2633 extern int D3D_textures_in;
2634 extern int Glide_textures_in;
2635 extern int Glide_textures_in_frame;
2636 extern int Glide_explosion_vram;
2637 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2639 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2641 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2650 if ( Show_player_pos ) {
2654 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));
2657 MONITOR_INC(NumPolys, modelstats_num_polys);
2658 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2659 MONITOR_INC(NumVerts, modelstats_num_verts );
2661 modelstats_num_polys = 0;
2662 modelstats_num_polys_drawn = 0;
2663 modelstats_num_verts = 0;
2664 modelstats_num_sortnorms = 0;
2668 void game_show_standalone_framerate()
2670 float frame_rate=30.0f;
2671 if ( frame_int == -1 ) {
2673 for (i=0; i<FRAME_FILTER; i++ ) {
2674 frametimes[i] = 0.0f;
2679 frametotal -= frametimes[frame_int];
2680 frametotal += flFrametime;
2681 frametimes[frame_int] = flFrametime;
2682 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2684 if ( frametotal != 0.0 ) {
2685 if ( Framecount >= FRAME_FILTER ){
2686 frame_rate = FRAME_FILTER / frametotal;
2688 frame_rate = Framecount / frametotal;
2691 std_set_standalone_fps(frame_rate);
2695 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2696 void game_show_time_left()
2700 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2701 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2702 // checking how much time is left
2704 if ( Mission_end_time == -1 ){
2708 diff = f2i(Mission_end_time - Missiontime);
2709 // be sure to bash to 0. diff could be negative on frame that we quit mission
2714 hud_set_default_color();
2715 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2718 //========================================================================================
2719 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2720 //========================================================================================
2724 DCF(ai_pause,"Pauses ai")
2727 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2728 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2729 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2730 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2733 obj_init_all_ships_physics();
2736 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2737 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2740 DCF(single_step,"Single steps the game")
2743 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2744 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2745 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2746 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2748 last_single_step = 0; // Make so single step waits a frame before stepping
2751 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2752 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2755 DCF_BOOL(physics_pause, physics_paused)
2756 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2757 DCF_BOOL(ai_firing, Ai_firing_enabled )
2759 // Create some simple aliases to these commands...
2760 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2761 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2762 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2763 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2764 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2767 //========================================================================================
2768 //========================================================================================
2771 void game_training_pause_do()
2775 key = game_check_key();
2777 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2784 void game_increase_skill_level()
2787 if (Game_skill_level >= NUM_SKILL_LEVELS){
2788 Game_skill_level = 0;
2792 int Player_died_time;
2794 int View_percent = 100;
2797 DCF(view, "Sets the percent of the 3d view to render.")
2800 dc_get_arg(ARG_INT);
2801 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2802 View_percent = Dc_arg_int;
2804 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2810 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2814 dc_printf("View is set to %d%%\n", View_percent );
2819 // Set the clip region for the 3d rendering window
2820 void game_set_view_clip()
2822 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2823 // Set the clip region for the letterbox "dead view"
2824 int yborder = gr_screen.max_h/4;
2826 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2827 // J.S. I've changed my ways!! See the new "no constants" code!!!
2828 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2830 // Set the clip region for normal view
2831 if ( View_percent >= 100 ) {
2834 int xborder, yborder;
2836 if ( View_percent < 5 ) {
2840 float fp = i2fl(View_percent)/100.0f;
2841 int fi = fl2i(fl_sqrt(fp)*100.0f);
2842 if ( fi > 100 ) fi=100;
2844 xborder = ( gr_screen.max_w*(100-fi) )/200;
2845 yborder = ( gr_screen.max_h*(100-fi) )/200;
2847 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2853 void show_debug_stuff()
2856 int laser_count = 0, missile_count = 0;
2858 for (i=0; i<MAX_OBJECTS; i++) {
2859 if (Objects[i].type == OBJ_WEAPON){
2860 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2862 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2868 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2871 extern int Tool_enabled;
2876 int tst_bitmap = -1;
2878 float tst_offset, tst_offset_total;
2881 void game_tst_frame_pre()
2889 g3_rotate_vertex(&v, &tst_pos);
2890 g3_project_vertex(&v);
2893 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2897 // big ship? always tst
2899 // within 3000 meters
2900 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2904 // within 300 meters
2905 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2912 void game_tst_frame()
2922 tst_time = time(NULL);
2924 // load the tst bitmap
2925 switch((int)frand_range(0.0f, 3.0)){
2927 tst_bitmap = bm_load("ig_jim");
2929 mprintf(("TST 0\n"));
2933 tst_bitmap = bm_load("ig_kan");
2935 mprintf(("TST 1\n"));
2939 tst_bitmap = bm_load("ig_jim");
2941 mprintf(("TST 2\n"));
2945 tst_bitmap = bm_load("ig_kan");
2947 mprintf(("TST 3\n"));
2956 // get the tst bitmap dimensions
2958 bm_get_info(tst_bitmap, &w, &h);
2961 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2963 snd_play(&Snds[SND_VASUDAN_BUP]);
2965 // tst x and direction
2969 tst_offset_total = (float)w;
2970 tst_offset = (float)w;
2972 tst_x = (float)gr_screen.max_w;
2973 tst_offset_total = (float)-w;
2974 tst_offset = (float)w;
2982 float diff = (tst_offset_total / 0.5f) * flFrametime;
2988 tst_offset -= fl_abs(diff);
2989 } else if(tst_mode == 2){
2992 tst_offset -= fl_abs(diff);
2996 gr_set_bitmap(tst_bitmap);
2997 gr_bitmap((int)tst_x, (int)tst_y);
3000 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3004 // if we passed the switch point
3005 if(tst_offset <= 0.0f){
3010 tst_stamp = timestamp(1000);
3011 tst_offset = fl_abs(tst_offset_total);
3022 void game_tst_mark(object *objp, ship *shipp)
3031 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3034 sip = &Ship_info[shipp->ship_info_index];
3041 tst_pos = objp->pos;
3042 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3048 extern void render_shields();
3050 void player_repair_frame(float frametime)
3052 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3054 for(idx=0;idx<MAX_PLAYERS;idx++){
3057 np = &Net_players[idx];
3059 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)){
3061 // don't rearm/repair if the player is dead or dying/departing
3062 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3063 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3068 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3069 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3075 #define NUM_FRAMES_TEST 300
3076 #define NUM_MIXED_SOUNDS 16
3077 void do_timing_test(float flFrametime)
3079 static int framecount = 0;
3080 static int test_running = 0;
3081 static float test_time = 0.0f;
3083 static int snds[NUM_MIXED_SOUNDS];
3086 if ( test_running ) {
3088 test_time += flFrametime;
3089 if ( framecount >= NUM_FRAMES_TEST ) {
3091 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3092 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3097 if ( Test_begin == 1 ) {
3103 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3106 // start looping digital sounds
3107 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3108 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3115 DCF(dcf_fov, "Change the field of view")
3118 dc_get_arg(ARG_FLOAT|ARG_NONE);
3119 if ( Dc_arg_type & ARG_NONE ) {
3120 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3121 dc_printf( "Zoom factor reset\n" );
3123 if ( Dc_arg_type & ARG_FLOAT ) {
3124 if (Dc_arg_float < 0.25f) {
3125 Viewer_zoom = 0.25f;
3126 dc_printf("Zoom factor pinned at 0.25.\n");
3127 } else if (Dc_arg_float > 1.25f) {
3128 Viewer_zoom = 1.25f;
3129 dc_printf("Zoom factor pinned at 1.25.\n");
3131 Viewer_zoom = Dc_arg_float;
3137 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3140 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3144 DCF(framerate_cap, "Sets the framerate cap")
3147 dc_get_arg(ARG_INT);
3148 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3149 Framerate_cap = Dc_arg_int;
3151 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3157 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3158 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3159 dc_printf("[n] must be from 1 to 120.\n");
3163 if ( Framerate_cap )
3164 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3166 dc_printf("There is no framerate cap currently active.\n");
3170 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3171 int Show_viewing_from_self = 0;
3173 void say_view_target()
3175 object *view_target;
3177 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3178 view_target = &Objects[Player_ai->target_objnum];
3180 view_target = Player_obj;
3182 if (Game_mode & GM_DEAD) {
3183 if (Player_ai->target_objnum != -1)
3184 view_target = &Objects[Player_ai->target_objnum];
3187 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3188 if (view_target != Player_obj){
3190 char *view_target_name = NULL;
3191 switch(Objects[Player_ai->target_objnum].type) {
3193 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3196 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3197 Viewer_mode &= ~VM_OTHER_SHIP;
3199 case OBJ_JUMP_NODE: {
3200 char jump_node_name[128];
3201 strcpy(jump_node_name, XSTR( "jump node", 184));
3202 view_target_name = jump_node_name;
3203 Viewer_mode &= ~VM_OTHER_SHIP;
3212 if ( view_target_name ) {
3213 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3214 Show_viewing_from_self = 1;
3217 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3218 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3219 Show_viewing_from_self = 1;
3221 if (Show_viewing_from_self)
3222 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3227 Last_view_target = view_target;
3231 float Game_hit_x = 0.0f;
3232 float Game_hit_y = 0.0f;
3234 // Reset at the beginning of each frame
3235 void game_whack_reset()
3241 // Apply a 2d whack to the player
3242 void game_whack_apply( float x, float y )
3244 // Do some force feedback
3245 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3251 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3254 // call to apply a "shudder"
3255 void game_shudder_apply(int time, float intensity)
3257 Game_shudder_time = timestamp(time);
3258 Game_shudder_total = time;
3259 Game_shudder_intensity = intensity;
3262 #define FF_SCALE 10000
3263 void apply_hud_shake(matrix *eye_orient)
3265 if (Viewer_obj == Player_obj) {
3266 physics_info *pi = &Player_obj->phys_info;
3274 // Make eye shake due to afterburner
3275 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3278 dtime = timestamp_until(pi->afterburner_decay);
3282 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3283 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3286 // Make eye shake due to engine wash
3288 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3291 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3292 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3294 // get the intensity
3295 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3299 vm_vec_rand_vec_quick(&rand_vec);
3302 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3306 // make hud shake due to shuddering
3307 if(Game_shudder_time != -1){
3308 // if the timestamp has elapsed
3309 if(timestamp_elapsed(Game_shudder_time)){
3310 Game_shudder_time = -1;
3312 // otherwise apply some shudder
3316 dtime = timestamp_until(Game_shudder_time);
3320 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));
3321 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));
3326 vm_angles_2_matrix(&tm, &tangles);
3327 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3328 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3329 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3330 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3335 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3337 // Player's velocity just before he blew up. Used to keep camera target moving.
3338 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3340 // Set eye_pos and eye_orient based on view mode.
3341 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3345 static int last_Viewer_mode = 0;
3346 static int last_Game_mode = 0;
3347 static int last_Viewer_objnum = -1;
3349 // This code is supposed to detect camera "cuts"... like going between
3352 // determine if we need to regenerate the nebula
3353 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3354 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3355 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3356 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3357 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3358 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3359 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3360 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3361 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3364 // regenerate the nebula
3368 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3369 //mprintf(( "************** Camera cut! ************\n" ));
3370 last_Viewer_mode = Viewer_mode;
3371 last_Game_mode = Game_mode;
3373 // Camera moved. Tell stars & debris to not do blurring.
3379 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3380 player_display_packlock_view();
3383 game_set_view_clip();
3385 if (Game_mode & GM_DEAD) {
3386 vector vec_to_deader, view_pos;
3389 Viewer_mode |= VM_DEAD_VIEW;
3391 if (Player_ai->target_objnum != -1) {
3392 int view_from_player = 1;
3394 if (Viewer_mode & VM_OTHER_SHIP) {
3395 // View from target.
3396 Viewer_obj = &Objects[Player_ai->target_objnum];
3398 last_Viewer_objnum = Player_ai->target_objnum;
3400 if ( Viewer_obj->type == OBJ_SHIP ) {
3401 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3402 view_from_player = 0;
3405 last_Viewer_objnum = -1;
3408 if ( view_from_player ) {
3409 // View target from player ship.
3411 *eye_pos = Player_obj->pos;
3412 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3413 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3416 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3418 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3419 dist += flFrametime * 16.0f;
3421 vm_vec_scale(&vec_to_deader, -dist);
3422 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3424 view_pos = Player_obj->pos;
3426 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3427 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3428 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3429 Dead_player_last_vel = Player_obj->phys_info.vel;
3430 //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));
3431 } else if (Player_ai->target_objnum != -1) {
3432 view_pos = Objects[Player_ai->target_objnum].pos;
3434 // Make camera follow explosion, but gradually slow down.
3435 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3436 view_pos = Player_obj->pos;
3437 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3438 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3441 *eye_pos = Dead_camera_pos;
3443 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3445 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3450 // if supernova shockwave
3451 if(supernova_camera_cut()){
3455 // call it dead view
3456 Viewer_mode |= VM_DEAD_VIEW;
3458 // set eye pos and orient
3459 supernova_set_view(eye_pos, eye_orient);
3461 // If already blown up, these other modes can override.
3462 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3463 Viewer_mode &= ~VM_DEAD_VIEW;
3465 Viewer_obj = Player_obj;
3467 if (Viewer_mode & VM_OTHER_SHIP) {
3468 if (Player_ai->target_objnum != -1){
3469 Viewer_obj = &Objects[Player_ai->target_objnum];
3470 last_Viewer_objnum = Player_ai->target_objnum;
3472 Viewer_mode &= ~VM_OTHER_SHIP;
3473 last_Viewer_objnum = -1;
3476 last_Viewer_objnum = -1;
3479 if (Viewer_mode & VM_EXTERNAL) {
3482 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3483 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3485 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3487 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3488 vm_vec_normalize(&eye_dir);
3489 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3492 // Modify the orientation based on head orientation.
3493 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3495 } else if ( Viewer_mode & VM_CHASE ) {
3498 if ( Viewer_obj->phys_info.speed < 0.1 )
3499 move_dir = Viewer_obj->orient.fvec;
3501 move_dir = Viewer_obj->phys_info.vel;
3502 vm_vec_normalize(&move_dir);
3505 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3506 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3507 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3508 vm_vec_normalize(&eye_dir);
3510 // JAS: I added the following code because if you slew up using
3511 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3512 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3513 // call because the up and the forward vector are the same. I fixed
3514 // it by adding in a fraction of the right vector all the time to the
3516 vector tmp_up = Viewer_obj->orient.uvec;
3517 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3519 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3522 // Modify the orientation based on head orientation.
3523 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3524 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3525 *eye_pos = Camera_pos;
3527 ship * shipp = &Ships[Player_obj->instance];
3529 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3530 vm_vec_normalize(&eye_dir);
3531 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3534 // get an eye position based upon the correct type of object
3535 switch(Viewer_obj->type){
3537 // make a call to get the eye point for the player object
3538 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3541 // make a call to get the eye point for the player object
3542 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3548 #ifdef JOHNS_DEBUG_CODE
3549 john_debug_stuff(&eye_pos, &eye_orient);
3555 apply_hud_shake(eye_orient);
3557 // setup neb2 rendering
3558 neb2_render_setup(eye_pos, eye_orient);
3562 extern void ai_debug_render_stuff();
3565 int Game_subspace_effect = 0;
3566 DCF_BOOL( subspace, Game_subspace_effect );
3568 // Does everything needed to render a frame
3569 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3573 g3_start_frame(game_zbuffer);
3574 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3576 // maybe offset the HUD (jitter stuff)
3577 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3578 HUD_set_offsets(Viewer_obj, !dont_offset);
3580 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3581 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3582 // must be done before ships are rendered
3583 if ( MULTIPLAYER_CLIENT ) {
3584 shield_point_multi_setup();
3587 if ( Game_subspace_effect ) {
3588 stars_draw(0,0,0,1);
3590 stars_draw(1,1,1,0);
3593 obj_render_all(obj_render);
3594 beam_render_all(); // render all beam weapons
3595 particle_render_all(); // render particles after everything else.
3596 trail_render_all(); // render missilie trails after everything else.
3597 mflash_render_all(); // render all muzzle flashes
3599 // Why do we not show the shield effect in these modes? Seems ok.
3600 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3604 // render nebula lightning
3607 // render local player nebula
3608 neb2_render_player();
3611 ai_debug_render_stuff();
3614 #ifndef RELEASE_REAL
3615 // game_framerate_check();
3619 extern void snd_spew_debug_info();
3620 snd_spew_debug_info();
3623 //================ END OF 3D RENDERING STUFF ====================
3627 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3628 hud_maybe_clear_head_area();
3629 anim_render_all(0, flFrametime);
3632 extern int Multi_display_netinfo;
3633 if(Multi_display_netinfo){
3634 extern void multi_display_netinfo();
3635 multi_display_netinfo();
3638 game_tst_frame_pre();
3641 do_timing_test(flFrametime);
3645 extern int OO_update_index;
3646 multi_rate_display(OO_update_index, 375, 0);
3651 extern void oo_display();
3658 //#define JOHNS_DEBUG_CODE 1
3660 #ifdef JOHNS_DEBUG_CODE
3661 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3663 //if ( keyd_pressed[KEY_LSHIFT] )
3665 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3667 model_subsystem *turret = tsys->system_info;
3669 if (turret->type == SUBSYSTEM_TURRET ) {
3671 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3673 ship_model_start(tobj);
3675 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3676 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3677 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3679 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3681 ship_model_stop(tobj);
3691 // following function for dumping frames for purposes of building trailers.
3694 // function to toggle state of dumping every frame into PCX when playing the game
3695 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3699 if ( Debug_dump_frames == 0 ) {
3701 Debug_dump_frames = 15;
3702 Debug_dump_trigger = 0;
3703 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3704 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3707 Debug_dump_frames = 0;
3708 Debug_dump_trigger = 0;
3709 gr_dump_frame_stop();
3710 dc_printf( "Frame dumping is now OFF\n" );
3716 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3720 if ( Debug_dump_frames == 0 ) {
3722 Debug_dump_frames = 15;
3723 Debug_dump_trigger = 1;
3724 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3725 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3728 Debug_dump_frames = 0;
3729 Debug_dump_trigger = 0;
3730 gr_dump_frame_stop();
3731 dc_printf( "Frame dumping is now OFF\n" );
3737 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3741 if ( Debug_dump_frames == 0 ) {
3743 Debug_dump_frames = 30;
3744 Debug_dump_trigger = 0;
3745 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3746 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3749 Debug_dump_frames = 0;
3750 Debug_dump_trigger = 0;
3751 gr_dump_frame_stop();
3752 dc_printf( "Frame dumping is now OFF\n" );
3758 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3762 if ( Debug_dump_frames == 0 ) {
3764 Debug_dump_frames = 30;
3765 Debug_dump_trigger = 1;
3766 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3767 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3770 Debug_dump_frames = 0;
3771 Debug_dump_trigger = 0;
3772 gr_dump_frame_stop();
3773 dc_printf( "Triggered frame dumping is now OFF\n" );
3779 void game_maybe_dump_frame()
3781 if ( !Debug_dump_frames ){
3785 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3792 Debug_dump_frame_num++;
3798 extern int Player_dead_state;
3800 // Flip the page and time how long it took.
3801 void game_flip_page_and_time_it()
3805 t1 = timer_get_fixed_seconds();
3807 t2 = timer_get_fixed_seconds();
3809 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3810 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3813 void game_simulation_frame()
3815 // blow ships up in multiplayer dogfight
3816 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){
3817 // blow up all non-player ships
3818 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3821 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3823 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)){
3824 moveup = GET_NEXT(moveup);
3827 shipp = &Ships[Objects[moveup->objnum].instance];
3828 sip = &Ship_info[shipp->ship_info_index];
3830 // only blow up small ships
3831 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3832 // function to simply explode a ship where it is currently at
3833 ship_self_destruct( &Objects[moveup->objnum] );
3836 moveup = GET_NEXT(moveup);
3842 // process AWACS stuff - do this first thing
3845 // single player, set Player hits_this_frame to 0
3846 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3847 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3848 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3852 supernova_process();
3853 if(supernova_active() >= 5){
3857 // fire targeting lasers now so that
3858 // 1 - created this frame
3859 // 2 - collide this frame
3860 // 3 - render this frame
3861 // 4 - ignored and deleted next frame
3862 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3864 ship_process_targeting_lasers();
3866 // do this here so that it works for multiplayer
3868 // get viewer direction
3869 int viewer_direction = PHYSICS_VIEWER_REAR;
3871 if(Viewer_mode == 0){
3872 viewer_direction = PHYSICS_VIEWER_FRONT;
3874 if(Viewer_mode & VM_PADLOCK_UP){
3875 viewer_direction = PHYSICS_VIEWER_UP;
3877 else if(Viewer_mode & VM_PADLOCK_REAR){
3878 viewer_direction = PHYSICS_VIEWER_REAR;
3880 else if(Viewer_mode & VM_PADLOCK_LEFT){
3881 viewer_direction = PHYSICS_VIEWER_LEFT;
3883 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3884 viewer_direction = PHYSICS_VIEWER_RIGHT;
3887 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3889 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3892 #define VM_PADLOCK_UP (1 << 7)
3893 #define VM_PADLOCK_REAR (1 << 8)
3894 #define VM_PADLOCK_LEFT (1 << 9)
3895 #define VM_PADLOCK_RIGHT (1 << 10)
3897 // evaluate mission departures and arrivals before we process all objects.
3898 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3900 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3901 // ships/wing packets.
3902 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3903 mission_parse_eval_stuff();
3906 // if we're an observer, move ourselves seperately from the standard physics
3907 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3908 obj_observer_move(flFrametime);
3911 // move all the objects now
3912 obj_move_all(flFrametime);
3914 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3915 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3916 // ship_check_cargo_all();
3917 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3918 mission_eval_goals();
3922 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3923 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3924 training_check_objectives();
3927 // do all interpolation now
3928 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3929 // client side processing of warping in effect stages
3930 multi_do_client_warp(flFrametime);
3932 // client side movement of an observer
3933 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3934 obj_observer_move(flFrametime);
3937 // move all objects - does interpolation now as well
3938 obj_move_all(flFrametime);
3941 // only process the message queue when the player is "in" the game
3942 if ( !Pre_player_entry ){
3943 message_queue_process(); // process any messages send to the player
3946 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3947 message_maybe_distort(); // maybe distort incoming message if comms damaged
3948 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3949 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3950 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3953 if(!(Game_mode & GM_STANDALONE_SERVER)){
3954 // process some stuff every frame (before frame is rendered)
3955 emp_process_local();
3957 hud_update_frame(); // update hud systems
3959 if (!physics_paused) {
3960 // Move particle system
3961 particle_move_all(flFrametime);
3963 // Move missile trails
3964 trail_move_all(flFrametime);
3966 // process muzzle flashes
3967 mflash_process_all();
3969 // Flash the gun flashes
3970 shipfx_flash_do_frame(flFrametime);
3972 shockwave_move_all(flFrametime); // update all the shockwaves
3975 // subspace missile strikes
3978 obj_snd_do_frame(); // update the object-linked persistant sounds
3979 game_maybe_update_sound_environment();
3980 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3982 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3984 if ( Game_subspace_effect ) {
3985 game_start_subspace_ambient_sound();
3991 // Maybe render and process the dead-popup
3992 void game_maybe_do_dead_popup(float frametime)
3994 if ( popupdead_is_active() ) {
3996 int choice = popupdead_do_frame(frametime);
3998 if ( Game_mode & GM_NORMAL ) {
4002 if(game_do_cd_mission_check(Game_current_mission_filename)){
4003 gameseq_post_event(GS_EVENT_ENTER_GAME);
4005 gameseq_post_event(GS_EVENT_MAIN_MENU);
4010 gameseq_post_event(GS_EVENT_END_GAME);
4015 if(game_do_cd_mission_check(Game_current_mission_filename)){
4016 gameseq_post_event(GS_EVENT_START_GAME);
4018 gameseq_post_event(GS_EVENT_MAIN_MENU);
4022 // this should only happen during a red alert mission
4025 Assert(The_mission.red_alert);
4026 if(!The_mission.red_alert){
4028 if(game_do_cd_mission_check(Game_current_mission_filename)){
4029 gameseq_post_event(GS_EVENT_START_GAME);
4031 gameseq_post_event(GS_EVENT_MAIN_MENU);
4036 // choose the previous mission
4037 mission_campaign_previous_mission();
4039 if(game_do_cd_mission_check(Game_current_mission_filename)){
4040 gameseq_post_event(GS_EVENT_START_GAME);
4042 gameseq_post_event(GS_EVENT_MAIN_MENU);
4053 case POPUPDEAD_DO_MAIN_HALL:
4054 multi_quit_game(PROMPT_NONE,-1);
4057 case POPUPDEAD_DO_RESPAWN:
4058 multi_respawn_normal();
4059 event_music_player_respawn();
4062 case POPUPDEAD_DO_OBSERVER:
4063 multi_respawn_observer();
4064 event_music_player_respawn_as_observer();
4073 if ( leave_popup ) {
4079 // returns true if player is actually in a game_play stats
4080 int game_actually_playing()
4084 state = gameseq_get_state();
4085 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4091 // Draw the 2D HUD gauges
4092 void game_render_hud_2d()
4094 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4098 HUD_render_2d(flFrametime);
4102 // Draw the 3D-dependant HUD gauges
4103 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4105 g3_start_frame(0); // 0 = turn zbuffering off
4106 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4108 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4109 HUD_render_3d(flFrametime);
4113 game_sunspot_process(flFrametime);
4115 // Diminish the palette effect
4116 game_flash_diminish(flFrametime);
4124 int actually_playing;
4125 fix total_time1, total_time2;
4126 fix render2_time1=0, render2_time2=0;
4127 fix render3_time1=0, render3_time2=0;
4128 fix flip_time1=0, flip_time2=0;
4129 fix clear_time1=0, clear_time2=0;
4135 if (Framerate_delay) {
4136 int start_time = timer_get_milliseconds();
4137 while (timer_get_milliseconds() < start_time + Framerate_delay)
4143 demo_do_frame_start();
4145 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4150 // start timing frame
4151 timing_frame_start();
4153 total_time1 = timer_get_fixed_seconds();
4155 // var to hold which state we are in
4156 actually_playing = game_actually_playing();
4158 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4159 if (!(Game_mode & GM_STANDALONE_SERVER)){
4160 Assert( OBJ_INDEX(Player_obj) >= 0 );
4164 if (Missiontime > Entry_delay_time){
4165 Pre_player_entry = 0;
4167 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4170 // Note: These are done even before the player enters, else buffers can overflow.
4171 if (! (Game_mode & GM_STANDALONE_SERVER)){
4175 shield_frame_init();
4177 if ( Player->control_mode != PCM_NORMAL )
4180 if ( !Pre_player_entry && actually_playing ) {
4181 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4183 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4184 game_process_keys();
4186 // don't read flying controls if we're playing a demo back
4187 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4188 read_player_controls( Player_obj, flFrametime);
4192 // if we're not the master, we may have to send the server-critical ship status button_info bits
4193 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4194 multi_maybe_send_ship_status();
4199 // Reset the whack stuff
4202 // These two lines must be outside of Pre_player_entry code,
4203 // otherwise too many lights are added.
4206 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4210 game_simulation_frame();
4212 // if not actually in a game play state, then return. This condition could only be true in
4213 // a multiplayer game.
4214 if ( !actually_playing ) {
4215 Assert( Game_mode & GM_MULTIPLAYER );
4219 if (!Pre_player_entry) {
4220 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4221 clear_time1 = timer_get_fixed_seconds();
4222 // clear the screen to black
4224 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4228 clear_time2 = timer_get_fixed_seconds();
4229 render3_time1 = timer_get_fixed_seconds();
4230 game_render_frame_setup(&eye_pos, &eye_orient);
4231 game_render_frame( &eye_pos, &eye_orient );
4233 // save the eye position and orientation
4234 if ( Game_mode & GM_MULTIPLAYER ) {
4235 Net_player->s_info.eye_pos = eye_pos;
4236 Net_player->s_info.eye_orient = eye_orient;
4239 hud_show_target_model();
4241 // check to see if we should display the death died popup
4242 if(Game_mode & GM_DEAD_BLEW_UP){
4243 if(Game_mode & GM_MULTIPLAYER){
4244 // catch the situation where we're supposed to be warping out on this transition
4245 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4246 gameseq_post_event(GS_EVENT_DEBRIEF);
4247 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4248 Player_died_popup_wait = -1;
4252 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4253 Player_died_popup_wait = -1;
4259 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4260 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4261 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4262 if(!popupdead_is_active()){
4266 Player_multi_died_check = -1;
4270 render3_time2 = timer_get_fixed_seconds();
4271 render2_time1 = timer_get_fixed_seconds();
4274 game_get_framerate();
4275 game_show_framerate();
4277 game_show_time_left();
4279 // Draw the 2D HUD gauges
4280 if(supernova_active() < 3){
4281 game_render_hud_2d();
4284 game_set_view_clip();
4286 // Draw 3D HUD gauges
4287 game_render_hud_3d(&eye_pos, &eye_orient);
4291 render2_time2 = timer_get_fixed_seconds();
4293 // maybe render and process the dead popup
4294 game_maybe_do_dead_popup(flFrametime);
4296 // start timing frame
4297 timing_frame_stop();
4298 // timing_display(30, 10);
4300 // If a regular popup is active, don't flip (popup code flips)
4301 if( !popup_running_state() ){
4302 flip_time1 = timer_get_fixed_seconds();
4303 game_flip_page_and_time_it();
4304 flip_time2 = timer_get_fixed_seconds();
4308 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4311 game_show_standalone_framerate();
4315 game_do_training_checks();
4318 // process lightning (nebula only)
4321 total_time2 = timer_get_fixed_seconds();
4323 // Got some timing numbers
4324 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4325 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4326 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4327 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4328 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4331 demo_do_frame_end();
4333 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4339 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4340 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4341 // died. This resulted in screwed up death sequences.
4343 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4344 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4345 static int timer_paused=0;
4346 #if defined(TIMER_TEST) && !defined(NDEBUG)
4347 static int stop_count,start_count;
4348 static int time_stopped,time_started;
4350 int saved_timestamp_ticker = -1;
4352 void game_reset_time()
4354 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4358 // Last_time = timer_get_fixed_seconds();
4364 void game_stop_time()
4366 if (timer_paused==0) {
4368 time = timer_get_fixed_seconds();
4369 // Save how much time progressed so far in the frame so we can
4370 // use it when we unpause.
4371 Last_delta_time = time - Last_time;
4373 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4374 if (Last_delta_time < 0) {
4375 #if defined(TIMER_TEST) && !defined(NDEBUG)
4376 Int3(); //get Matt!!!!
4378 Last_delta_time = 0;
4380 #if defined(TIMER_TEST) && !defined(NDEBUG)
4381 time_stopped = time;
4384 // Stop the timer_tick stuff...
4385 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4386 saved_timestamp_ticker = timestamp_ticker;
4390 #if defined(TIMER_TEST) && !defined(NDEBUG)
4395 void game_start_time()
4398 Assert(timer_paused >= 0);
4399 if (timer_paused==0) {
4401 time = timer_get_fixed_seconds();
4402 #if defined(TIMER_TEST) && !defined(NDEBUG)
4404 Int3(); //get Matt!!!!
4407 // Take current time, and set it backwards to account for time
4408 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4409 // will be correct when it goes to calculate the frametime next
4411 Last_time = time - Last_delta_time;
4412 #if defined(TIMER_TEST) && !defined(NDEBUG)
4413 time_started = time;
4416 // Restore the timer_tick stuff...
4417 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4418 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4419 timestamp_ticker = saved_timestamp_ticker;
4420 saved_timestamp_ticker = -1;
4423 #if defined(TIMER_TEST) && !defined(NDEBUG)
4429 void game_set_frametime(int state)
4432 float frame_cap_diff;
4434 thistime = timer_get_fixed_seconds();
4436 if ( Last_time == 0 )
4437 Frametime = F1_0 / 30;
4439 Frametime = thistime - Last_time;
4441 // Frametime = F1_0 / 30;
4443 fix debug_frametime = Frametime; // Just used to display frametime.
4445 // If player hasn't entered mission yet, make frame take 1/4 second.
4446 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4449 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4451 fix frame_speed = F1_0 / Debug_dump_frames;
4453 if (Frametime > frame_speed ){
4454 nprintf(("warning","slow frame: %x\n",Frametime));
4457 thistime = timer_get_fixed_seconds();
4458 Frametime = thistime - Last_time;
4459 } while (Frametime < frame_speed );
4461 Frametime = frame_speed;
4465 Assert( Framerate_cap > 0 );
4467 // Cap the framerate so it doesn't get too high.
4471 cap = F1_0/Framerate_cap;
4472 if (Frametime < cap) {
4473 thistime = cap - Frametime;
4474 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4475 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4477 thistime = timer_get_fixed_seconds();
4481 if((Game_mode & GM_STANDALONE_SERVER) &&
4482 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4484 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4485 Sleep((DWORD)(frame_cap_diff*1000));
4487 thistime += fl2f((frame_cap_diff));
4489 Frametime = thistime - Last_time;
4492 // If framerate is too low, cap it.
4493 if (Frametime > MAX_FRAMETIME) {
4495 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4497 // to remove warnings in release build
4498 debug_frametime = fl2f(flFrametime);
4500 Frametime = MAX_FRAMETIME;
4503 Frametime = fixmul(Frametime, Game_time_compression);
4505 Last_time = thistime;
4506 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4508 flFrametime = f2fl(Frametime);
4509 //if(!(Game_mode & GM_PLAYING_DEMO)){
4510 timestamp_inc(flFrametime);
4512 /* if ((Framecount > 0) && (Framecount < 10)) {
4513 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4518 // This is called from game_do_frame(), and from navmap_do_frame()
4519 void game_update_missiontime()
4521 // TODO JAS: Put in if and move this into game_set_frametime,
4522 // fix navmap to call game_stop/start_time
4523 //if ( !timer_paused )
4524 Missiontime += Frametime;
4527 void game_do_frame()
4529 game_set_frametime(GS_STATE_GAME_PLAY);
4530 game_update_missiontime();
4532 if (Game_mode & GM_STANDALONE_SERVER) {
4533 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4536 if ( game_single_step && (last_single_step == game_single_step) ) {
4537 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4538 while( key_checkch() == 0 )
4540 os_set_title( XSTR( "FreeSpace", 171) );
4541 Last_time = timer_get_fixed_seconds();
4544 last_single_step = game_single_step;
4546 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4547 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4551 Keep_mouse_centered = 0;
4552 monitor_update(); // Update monitor variables
4555 void multi_maybe_do_frame()
4557 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4562 int Joymouse_button_status = 0;
4564 // Flush all input devices
4572 Joymouse_button_status = 0;
4574 //mprintf(("Game flush!\n" ));
4577 // function for multiplayer only which calls game_do_state_common() when running the
4579 void game_do_dc_networking()
4581 Assert( Game_mode & GM_MULTIPLAYER );
4583 game_do_state_common( gameseq_get_state() );
4586 // Call this whenever in a loop, or when you need to check for a keystroke.
4587 int game_check_key()
4593 // convert keypad enter to normal enter
4594 if ((k & KEY_MASK) == KEY_PADENTER)
4595 k = (k & ~KEY_MASK) | KEY_ENTER;
4602 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4603 static int Demo_show_trailer_timestamp = 0;
4605 void demo_reset_trailer_timer()
4607 Demo_show_trailer_timestamp = timer_get_milliseconds();
4610 void demo_maybe_show_trailer(int k)
4613 // if key pressed, reset demo trailer timer
4615 demo_reset_trailer_timer();
4619 // if mouse moved, reset demo trailer timer
4622 mouse_get_delta(&dx, &dy);
4623 if ( (dx > 0) || (dy > 0) ) {
4624 demo_reset_trailer_timer();
4628 // if joystick has moved, reset demo trailer timer
4631 joy_get_delta(&dx, &dy);
4632 if ( (dx > 0) || (dy > 0) ) {
4633 demo_reset_trailer_timer();
4637 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4638 // the low-level code. Ugly, I know... but was the simplest and most
4641 // if 30 seconds since last demo trailer time reset, launch movie
4642 if ( os_foreground() ) {
4643 int now = timer_get_milliseconds();
4644 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4645 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4647 movie_play( NOX("fstrailer2.mve") );
4648 demo_reset_trailer_timer();
4656 // same as game_check_key(), except this is used while actually in the game. Since there
4657 // generally are differences between game control keys and general UI keys, makes sense to
4658 // have seperate functions for each case. If you are not checking a game control while in a
4659 // mission, you should probably be using game_check_key() instead.
4664 if (!os_foreground()) {
4669 // If we're in a single player game, pause it.
4670 if (!(Game_mode & GM_MULTIPLAYER)){
4671 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4672 game_process_pause_key();
4680 demo_maybe_show_trailer(k);
4683 // Move the mouse cursor with the joystick.
4684 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4685 // Move the mouse cursor with the joystick
4689 joy_get_pos( &jx, &jy, &jz, &jr );
4691 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4692 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4695 mouse_get_real_pos( &mx, &my );
4696 mouse_set_pos( mx+dx, my+dy );
4701 m = mouse_down(MOUSE_LEFT_BUTTON);
4703 if ( j != Joymouse_button_status ) {
4704 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4705 Joymouse_button_status = j;
4707 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4708 } else if ( (!j) && (m) ) {
4709 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4714 // if we should be ignoring keys because of some multiplayer situations
4715 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4719 // If a popup is running, don't process all the Fn keys
4720 if( popup_active() ) {
4724 state = gameseq_get_state();
4726 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4729 case KEY_DEBUGGED + KEY_BACKSP:
4734 launch_context_help();
4739 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4741 // don't allow f2 while warping out in multiplayer
4742 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4747 case GS_STATE_INITIAL_PLAYER_SELECT:
4748 case GS_STATE_OPTIONS_MENU:
4749 case GS_STATE_HUD_CONFIG:
4750 case GS_STATE_CONTROL_CONFIG:
4751 case GS_STATE_DEATH_DIED:
4752 case GS_STATE_DEATH_BLEW_UP:
4753 case GS_STATE_VIEW_MEDALS:
4757 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4764 // hotkey selection screen -- only valid from briefing and beyond.
4767 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) ) {
4768 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4774 case KEY_DEBUGGED + KEY_F3:
4775 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4778 case KEY_DEBUGGED + KEY_F4:
4779 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4783 if(Game_mode & GM_MULTIPLAYER){
4784 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4785 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4789 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4790 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4796 case KEY_ESC | KEY_SHIFTED:
4797 // make sure to quit properly out of multiplayer
4798 if(Game_mode & GM_MULTIPLAYER){
4799 multi_quit_game(PROMPT_NONE);
4802 gameseq_post_event( GS_EVENT_QUIT_GAME );
4807 case KEY_DEBUGGED + KEY_P:
4810 case KEY_PRINT_SCRN:
4812 static int counter = 0;
4817 sprintf( tmp_name, NOX("screen%02d"), counter );
4819 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4820 gr_print_screen(tmp_name);
4828 case KEY_SHIFTED | KEY_ENTER: {
4830 #if !defined(NDEBUG)
4832 if ( Game_mode & GM_NORMAL ){
4836 // if we're in multiplayer mode, do some special networking
4837 if(Game_mode & GM_MULTIPLAYER){
4838 debug_console(game_do_dc_networking);
4845 if ( Game_mode & GM_NORMAL )
4859 gameseq_post_event(GS_EVENT_QUIT_GAME);
4862 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4865 void camera_set_position( vector *pos )
4870 void camera_set_orient( matrix *orient )
4872 Camera_orient = *orient;
4875 void camera_set_velocity( vector *vel, int instantaneous )
4877 Camera_desired_velocity.x = 0.0f;
4878 Camera_desired_velocity.y = 0.0f;
4879 Camera_desired_velocity.z = 0.0f;
4881 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4882 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4883 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4885 if ( instantaneous ) {
4886 Camera_velocity = Camera_desired_velocity;
4894 vector new_vel, delta_pos;
4896 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4897 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4898 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4900 Camera_velocity = new_vel;
4902 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4904 vm_vec_add2( &Camera_pos, &delta_pos );
4906 float ot = Camera_time+0.0f;
4908 Camera_time += flFrametime;
4910 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4913 tmp.z = 4.739f; // always go this fast forward.
4915 // pick x and y velocities so they are always on a
4916 // circle with a 25 m radius.
4918 float tmp_angle = frand()*PI2;
4920 tmp.x = 22.0f * (float)sin(tmp_angle);
4921 tmp.y = -22.0f * (float)cos(tmp_angle);
4923 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4925 //mprintf(( "Changing velocity!\n" ));
4926 camera_set_velocity( &tmp, 0 );
4929 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4930 vector tmp = { 0.0f, 0.0f, 0.0f };
4931 camera_set_velocity( &tmp, 0 );
4936 void end_demo_campaign_do()
4938 #if defined(FS2_DEMO)
4939 // show upsell screens
4940 demo_upsell_show_screens();
4941 #elif defined(OEM_BUILD)
4942 // show oem upsell screens
4943 oem_upsell_show_screens();
4946 // drop into main hall
4947 gameseq_post_event( GS_EVENT_MAIN_MENU );
4950 // All code to process events. This is the only place
4951 // that you should change the state of the game.
4952 void game_process_event( int current_state, int event )
4954 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4957 case GS_EVENT_SIMULATOR_ROOM:
4958 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4961 case GS_EVENT_MAIN_MENU:
4962 gameseq_set_state(GS_STATE_MAIN_MENU);
4965 case GS_EVENT_OPTIONS_MENU:
4966 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4969 case GS_EVENT_BARRACKS_MENU:
4970 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4973 case GS_EVENT_TECH_MENU:
4974 gameseq_set_state(GS_STATE_TECH_MENU);
4977 case GS_EVENT_TRAINING_MENU:
4978 gameseq_set_state(GS_STATE_TRAINING_MENU);
4981 case GS_EVENT_START_GAME:
4982 Select_default_ship = 0;
4983 Player_multi_died_check = -1;
4984 gameseq_set_state(GS_STATE_CMD_BRIEF);
4987 case GS_EVENT_START_BRIEFING:
4988 gameseq_set_state(GS_STATE_BRIEFING);
4991 case GS_EVENT_DEBRIEF:
4992 // did we end the campaign in the main freespace 2 single player campaign?
4993 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4994 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4996 gameseq_set_state(GS_STATE_DEBRIEF);
4999 Player_multi_died_check = -1;
5002 case GS_EVENT_SHIP_SELECTION:
5003 gameseq_set_state( GS_STATE_SHIP_SELECT );
5006 case GS_EVENT_WEAPON_SELECTION:
5007 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5010 case GS_EVENT_ENTER_GAME:
5012 // maybe start recording a demo
5014 demo_start_record("test.fsd");
5018 if (Game_mode & GM_MULTIPLAYER) {
5019 // if we're respawning, make sure we change the view mode so that the hud shows up
5020 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5024 gameseq_set_state(GS_STATE_GAME_PLAY);
5026 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5029 Player_multi_died_check = -1;
5031 // clear multiplayer button info
5032 extern button_info Multi_ship_status_bi;
5033 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5035 Start_time = f2fl(timer_get_approx_seconds());
5037 mprintf(("Entering game at time = %7.3f\n", Start_time));
5041 case GS_EVENT_START_GAME_QUICK:
5042 Select_default_ship = 1;
5043 gameseq_post_event(GS_EVENT_ENTER_GAME);
5047 case GS_EVENT_END_GAME:
5048 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5049 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5050 gameseq_set_state(GS_STATE_MAIN_MENU);
5055 Player_multi_died_check = -1;
5058 case GS_EVENT_QUIT_GAME:
5059 main_hall_stop_music();
5060 main_hall_stop_ambient();
5061 gameseq_set_state(GS_STATE_QUIT_GAME);
5063 Player_multi_died_check = -1;
5066 case GS_EVENT_GAMEPLAY_HELP:
5067 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5070 case GS_EVENT_PAUSE_GAME:
5071 gameseq_push_state(GS_STATE_GAME_PAUSED);
5074 case GS_EVENT_DEBUG_PAUSE_GAME:
5075 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5078 case GS_EVENT_TRAINING_PAUSE:
5079 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5082 case GS_EVENT_PREVIOUS_STATE:
5083 gameseq_pop_state();
5086 case GS_EVENT_TOGGLE_FULLSCREEN:
5087 #ifndef HARDWARE_ONLY
5089 if ( gr_screen.mode == GR_SOFTWARE ) {
5090 gr_init( GR_640, GR_DIRECTDRAW );
5091 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5092 gr_init( GR_640, GR_SOFTWARE );
5098 case GS_EVENT_TOGGLE_GLIDE:
5100 if ( gr_screen.mode != GR_GLIDE ) {
5101 gr_init( GR_640, GR_GLIDE );
5103 gr_init( GR_640, GR_SOFTWARE );
5108 case GS_EVENT_LOAD_MISSION_MENU:
5109 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5112 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5113 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5116 case GS_EVENT_HUD_CONFIG:
5117 gameseq_push_state( GS_STATE_HUD_CONFIG );
5120 case GS_EVENT_CONTROL_CONFIG:
5121 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5124 case GS_EVENT_DEATH_DIED:
5125 gameseq_set_state( GS_STATE_DEATH_DIED );
5128 case GS_EVENT_DEATH_BLEW_UP:
5129 if ( current_state == GS_STATE_DEATH_DIED ) {
5130 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5131 event_music_player_death();
5133 // multiplayer clients set their extra check here
5134 if(Game_mode & GM_MULTIPLAYER){
5135 // set the multi died absolute last chance check
5136 Player_multi_died_check = time(NULL);
5139 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5143 case GS_EVENT_NEW_CAMPAIGN:
5144 if (!mission_load_up_campaign()){
5145 readyroom_continue_campaign();
5148 Player_multi_died_check = -1;
5151 case GS_EVENT_CAMPAIGN_CHEAT:
5152 if (!mission_load_up_campaign()){
5154 // bash campaign value
5155 extern char Main_hall_campaign_cheat[512];
5158 // look for the mission
5159 for(idx=0; idx<Campaign.num_missions; idx++){
5160 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5161 Campaign.next_mission = idx;
5162 Campaign.prev_mission = idx - 1;
5169 readyroom_continue_campaign();
5172 Player_multi_died_check = -1;
5175 case GS_EVENT_CAMPAIGN_ROOM:
5176 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5179 case GS_EVENT_CMD_BRIEF:
5180 gameseq_set_state(GS_STATE_CMD_BRIEF);
5183 case GS_EVENT_RED_ALERT:
5184 gameseq_set_state(GS_STATE_RED_ALERT);
5187 case GS_EVENT_CREDITS:
5188 gameseq_set_state( GS_STATE_CREDITS );
5191 case GS_EVENT_VIEW_MEDALS:
5192 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5195 case GS_EVENT_SHOW_GOALS:
5196 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5199 case GS_EVENT_HOTKEY_SCREEN:
5200 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5203 // multiplayer stuff follow these comments
5205 case GS_EVENT_MULTI_JOIN_GAME:
5206 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5209 case GS_EVENT_MULTI_HOST_SETUP:
5210 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5213 case GS_EVENT_MULTI_CLIENT_SETUP:
5214 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5217 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5218 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5221 case GS_EVENT_MULTI_STD_WAIT:
5222 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5225 case GS_EVENT_STANDALONE_MAIN:
5226 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5229 case GS_EVENT_MULTI_PAUSE:
5230 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5233 case GS_EVENT_INGAME_PRE_JOIN:
5234 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5237 case GS_EVENT_EVENT_DEBUG:
5238 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5241 // Start a warpout where player automatically goes 70 no matter what
5242 // and can't cancel out of it.
5243 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5244 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5246 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5247 Player->saved_viewer_mode = Viewer_mode;
5248 Player->control_mode = PCM_WARPOUT_STAGE1;
5249 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5250 Warpout_time = 0.0f; // Start timer!
5253 case GS_EVENT_PLAYER_WARPOUT_START:
5254 if ( Player->control_mode != PCM_NORMAL ) {
5255 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5257 Player->saved_viewer_mode = Viewer_mode;
5258 Player->control_mode = PCM_WARPOUT_STAGE1;
5259 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5260 Warpout_time = 0.0f; // Start timer!
5261 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5265 case GS_EVENT_PLAYER_WARPOUT_STOP:
5266 if ( Player->control_mode != PCM_NORMAL ) {
5267 if ( !Warpout_forced ) { // cannot cancel forced warpout
5268 Player->control_mode = PCM_NORMAL;
5269 Viewer_mode = Player->saved_viewer_mode;
5270 hud_subspace_notify_abort();
5271 mprintf(( "Player put back to normal mode.\n" ));
5272 if ( Warpout_sound > -1 ) {
5273 snd_stop( Warpout_sound );
5280 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5281 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5282 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5283 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5285 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5286 shipfx_warpout_start( Player_obj );
5287 Player->control_mode = PCM_WARPOUT_STAGE2;
5288 Player->saved_viewer_mode = Viewer_mode;
5289 Viewer_mode |= VM_WARP_CHASE;
5291 vector tmp = Player_obj->pos;
5293 ship_get_eye( &tmp, &tmp_m, Player_obj );
5294 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5295 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5296 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5298 camera_set_position( &tmp );
5299 camera_set_orient( &Player_obj->orient );
5300 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5302 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5303 camera_set_velocity( &tmp_vel, 1);
5307 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5308 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5309 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5310 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5312 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5313 Player->control_mode = PCM_WARPOUT_STAGE3;
5317 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5318 mprintf(( "Player warped out. Going to debriefing!\n" ));
5319 Player->control_mode = PCM_NORMAL;
5320 Viewer_mode = Player->saved_viewer_mode;
5323 // we have a special debriefing screen for multiplayer furballs
5324 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5325 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5327 // do the normal debriefing for all other situations
5329 gameseq_post_event(GS_EVENT_DEBRIEF);
5333 case GS_EVENT_STANDALONE_POSTGAME:
5334 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5337 case GS_EVENT_INITIAL_PLAYER_SELECT:
5338 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5341 case GS_EVENT_GAME_INIT:
5342 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5343 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5345 // see if the command line option has been set to use the last pilot, and act acoordingly
5346 if( player_select_get_last_pilot() ) {
5347 // always enter the main menu -- do the automatic network startup stuff elsewhere
5348 // so that we still have valid checks for networking modes, etc.
5349 gameseq_set_state(GS_STATE_MAIN_MENU);
5351 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5356 case GS_EVENT_MULTI_MISSION_SYNC:
5357 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5360 case GS_EVENT_MULTI_START_GAME:
5361 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5364 case GS_EVENT_MULTI_HOST_OPTIONS:
5365 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5368 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5369 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5372 case GS_EVENT_TEAM_SELECT:
5373 gameseq_set_state(GS_STATE_TEAM_SELECT);
5376 case GS_EVENT_END_CAMPAIGN:
5377 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5380 case GS_EVENT_END_DEMO:
5381 gameseq_set_state(GS_STATE_END_DEMO);
5384 case GS_EVENT_LOOP_BRIEF:
5385 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5394 // Called when a state is being left.
5395 // The current state is still at old_state, but as soon as
5396 // this function leaves, then the current state will become
5397 // new state. You should never try to change the state
5398 // in here... if you think you need to, you probably really
5399 // need to post an event, not change the state.
5400 void game_leave_state( int old_state, int new_state )
5402 int end_mission = 1;
5404 switch (new_state) {
5405 case GS_STATE_GAME_PAUSED:
5406 case GS_STATE_DEBUG_PAUSED:
5407 case GS_STATE_OPTIONS_MENU:
5408 case GS_STATE_CONTROL_CONFIG:
5409 case GS_STATE_MISSION_LOG_SCROLLBACK:
5410 case GS_STATE_DEATH_DIED:
5411 case GS_STATE_SHOW_GOALS:
5412 case GS_STATE_HOTKEY_SCREEN:
5413 case GS_STATE_MULTI_PAUSED:
5414 case GS_STATE_TRAINING_PAUSED:
5415 case GS_STATE_EVENT_DEBUG:
5416 case GS_STATE_GAMEPLAY_HELP:
5417 end_mission = 0; // these events shouldn't end a mission
5421 switch (old_state) {
5422 case GS_STATE_BRIEFING:
5423 brief_stop_voices();
5424 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5425 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5426 && (new_state != GS_STATE_TEAM_SELECT) ){
5427 common_select_close();
5428 if ( new_state == GS_STATE_MAIN_MENU ) {
5429 freespace_stop_mission();
5433 // COMMAND LINE OPTION
5434 if (Cmdline_multi_stream_chat_to_file){
5435 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5436 cfclose(Multi_chat_stream);
5440 case GS_STATE_DEBRIEF:
5441 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5446 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5447 multi_df_debrief_close();
5450 case GS_STATE_LOAD_MISSION_MENU:
5451 mission_load_menu_close();
5454 case GS_STATE_SIMULATOR_ROOM:
5458 case GS_STATE_CAMPAIGN_ROOM:
5459 campaign_room_close();
5462 case GS_STATE_CMD_BRIEF:
5463 if (new_state == GS_STATE_OPTIONS_MENU) {
5468 if (new_state == GS_STATE_MAIN_MENU)
5469 freespace_stop_mission();
5474 case GS_STATE_RED_ALERT:
5478 case GS_STATE_SHIP_SELECT:
5479 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5480 new_state != GS_STATE_HOTKEY_SCREEN &&
5481 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5482 common_select_close();
5483 if ( new_state == GS_STATE_MAIN_MENU ) {
5484 freespace_stop_mission();
5489 case GS_STATE_WEAPON_SELECT:
5490 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5491 new_state != GS_STATE_HOTKEY_SCREEN &&
5492 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5493 common_select_close();
5494 if ( new_state == GS_STATE_MAIN_MENU ) {
5495 freespace_stop_mission();
5500 case GS_STATE_TEAM_SELECT:
5501 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5502 new_state != GS_STATE_HOTKEY_SCREEN &&
5503 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5504 common_select_close();
5505 if ( new_state == GS_STATE_MAIN_MENU ) {
5506 freespace_stop_mission();
5511 case GS_STATE_MAIN_MENU:
5512 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5519 case GS_STATE_OPTIONS_MENU:
5520 //game_start_time();
5521 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5522 multi_join_clear_game_list();
5524 options_menu_close();
5527 case GS_STATE_BARRACKS_MENU:
5528 if(new_state != GS_STATE_VIEW_MEDALS){
5533 case GS_STATE_MISSION_LOG_SCROLLBACK:
5534 hud_scrollback_close();
5537 case GS_STATE_TRAINING_MENU:
5538 training_menu_close();
5541 case GS_STATE_GAME_PLAY:
5542 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5543 player_save_target_and_weapon_link_prefs();
5544 game_stop_looped_sounds();
5547 sound_env_disable();
5548 joy_ff_stop_effects();
5550 // stop game time under certain conditions
5551 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5556 // shut down any recording or playing demos
5561 // when in multiplayer and going back to the main menu, send a leave game packet
5562 // right away (before calling stop mission). stop_mission was taking to long to
5563 // close mission down and I want people to get notified ASAP.
5564 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5565 multi_quit_game(PROMPT_NONE);
5568 freespace_stop_mission();
5569 Game_time_compression = F1_0;
5573 case GS_STATE_TECH_MENU:
5577 case GS_STATE_TRAINING_PAUSED:
5578 Training_num_lines = 0;
5579 // fall through to GS_STATE_GAME_PAUSED
5581 case GS_STATE_GAME_PAUSED:
5583 if ( end_mission ) {
5588 case GS_STATE_DEBUG_PAUSED:
5591 pause_debug_close();
5595 case GS_STATE_HUD_CONFIG:
5599 // join/start a game
5600 case GS_STATE_MULTI_JOIN_GAME:
5601 if(new_state != GS_STATE_OPTIONS_MENU){
5602 multi_join_game_close();
5606 case GS_STATE_MULTI_HOST_SETUP:
5607 case GS_STATE_MULTI_CLIENT_SETUP:
5608 // if this is just the host going into the options screen, don't do anything
5609 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5613 // close down the proper state
5614 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5615 multi_create_game_close();
5617 multi_game_client_setup_close();
5620 // COMMAND LINE OPTION
5621 if (Cmdline_multi_stream_chat_to_file){
5622 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5623 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5624 cfclose(Multi_chat_stream);
5629 case GS_STATE_CONTROL_CONFIG:
5630 control_config_close();
5633 case GS_STATE_DEATH_DIED:
5634 Game_mode &= ~GM_DEAD_DIED;
5636 // early end while respawning or blowing up in a multiplayer game
5637 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5639 freespace_stop_mission();
5643 case GS_STATE_DEATH_BLEW_UP:
5644 Game_mode &= ~GM_DEAD_BLEW_UP;
5646 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5647 // to determine if I should do anything.
5648 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5650 freespace_stop_mission();
5653 // if we are not respawing as an observer or as a player, our new state will not
5654 // be gameplay state.
5655 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5656 game_stop_time(); // hasn't been called yet!!
5657 freespace_stop_mission();
5663 case GS_STATE_CREDITS:
5667 case GS_STATE_VIEW_MEDALS:
5671 case GS_STATE_SHOW_GOALS:
5672 mission_show_goals_close();
5675 case GS_STATE_HOTKEY_SCREEN:
5676 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5677 mission_hotkey_close();
5681 case GS_STATE_MULTI_MISSION_SYNC:
5682 // if we're moving into the options menu, don't do anything
5683 if(new_state == GS_STATE_OPTIONS_MENU){
5687 Assert( Game_mode & GM_MULTIPLAYER );
5689 if ( new_state == GS_STATE_GAME_PLAY ){
5690 // palette_restore_palette();
5692 // change a couple of flags to indicate our state!!!
5693 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5694 send_netplayer_update_packet();
5696 // set the game mode
5697 Game_mode |= GM_IN_MISSION;
5701 case GS_STATE_VIEW_CUTSCENES:
5702 cutscenes_screen_close();
5705 case GS_STATE_MULTI_STD_WAIT:
5706 multi_standalone_wait_close();
5709 case GS_STATE_STANDALONE_MAIN:
5710 standalone_main_close();
5711 if(new_state == GS_STATE_MULTI_STD_WAIT){
5712 init_multiplayer_stats();
5716 case GS_STATE_MULTI_PAUSED:
5717 // if ( end_mission ){
5722 case GS_STATE_INGAME_PRE_JOIN:
5723 multi_ingame_select_close();
5726 case GS_STATE_STANDALONE_POSTGAME:
5727 multi_standalone_postgame_close();
5730 case GS_STATE_INITIAL_PLAYER_SELECT:
5731 player_select_close();
5734 case GS_STATE_MULTI_START_GAME:
5735 multi_start_game_close();
5738 case GS_STATE_MULTI_HOST_OPTIONS:
5739 multi_host_options_close();
5742 case GS_STATE_END_OF_CAMPAIGN:
5743 mission_campaign_end_close();
5746 case GS_STATE_LOOP_BRIEF:
5752 // Called when a state is being entered.
5753 // The current state is set to the state we're entering at
5754 // this point, and old_state is set to the state we're coming
5755 // from. You should never try to change the state
5756 // in here... if you think you need to, you probably really
5757 // need to post an event, not change the state.
5759 void game_enter_state( int old_state, int new_state )
5761 switch (new_state) {
5762 case GS_STATE_MAIN_MENU:
5763 // in multiplayer mode, be sure that we are not doing networking anymore.
5764 if ( Game_mode & GM_MULTIPLAYER ) {
5765 Assert( Net_player != NULL );
5766 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5769 Game_time_compression = F1_0;
5771 // determine which ship this guy is currently based on
5772 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5775 if (Player->on_bastion) {
5783 case GS_STATE_BRIEFING:
5784 main_hall_stop_music();
5785 main_hall_stop_ambient();
5787 if (Game_mode & GM_NORMAL) {
5788 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5789 // MWA: or from options or hotkey screens
5790 // JH: or if the command brief state already did this
5791 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5792 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5793 && (old_state != GS_STATE_CMD_BRIEF) ) {
5794 if ( !game_start_mission() ) // this should put us into a new state on failure!
5798 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5799 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5800 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5802 Game_time_compression = F1_0;
5804 if ( red_alert_mission() ) {
5805 gameseq_post_event(GS_EVENT_RED_ALERT);
5812 case GS_STATE_DEBRIEF:
5813 game_stop_looped_sounds();
5814 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5815 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5820 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5821 multi_df_debrief_init();
5824 case GS_STATE_LOAD_MISSION_MENU:
5825 mission_load_menu_init();
5828 case GS_STATE_SIMULATOR_ROOM:
5832 case GS_STATE_CAMPAIGN_ROOM:
5833 campaign_room_init();
5836 case GS_STATE_RED_ALERT:
5837 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5841 case GS_STATE_CMD_BRIEF: {
5842 int team_num = 0; // team number used as index for which cmd brief to use.
5844 if (old_state == GS_STATE_OPTIONS_MENU) {
5848 main_hall_stop_music();
5849 main_hall_stop_ambient();
5851 if (Game_mode & GM_NORMAL) {
5852 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5853 // MWA: or from options or hotkey screens
5854 // JH: or if the command brief state already did this
5855 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5856 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5857 if ( !game_start_mission() ) // this should put us into a new state on failure!
5862 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5863 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5864 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5866 cmd_brief_init(team_num);
5872 case GS_STATE_SHIP_SELECT:
5876 case GS_STATE_WEAPON_SELECT:
5877 weapon_select_init();
5880 case GS_STATE_TEAM_SELECT:
5884 case GS_STATE_GAME_PAUSED:
5889 case GS_STATE_DEBUG_PAUSED:
5890 // game_stop_time();
5891 // os_set_title("FreeSpace - PAUSED");
5894 case GS_STATE_TRAINING_PAUSED:
5901 case GS_STATE_OPTIONS_MENU:
5903 options_menu_init();
5906 case GS_STATE_GAME_PLAY:
5907 // coming from the gameplay state or the main menu, we might need to load the mission
5908 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5909 if ( !game_start_mission() ) // this should put us into a new state.
5914 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5915 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5916 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5917 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5918 (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) ) {
5919 // JAS: Used to do all paging here.
5923 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5927 main_hall_stop_music();
5928 main_hall_stop_ambient();
5929 event_music_first_pattern(); // start the first pattern
5932 // special code that restores player ship selection and weapons loadout when doing a quick start
5933 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5934 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5935 wss_direct_restore_loadout();
5939 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5940 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5941 event_music_first_pattern(); // start the first pattern
5944 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5945 event_music_first_pattern(); // start the first pattern
5947 player_restore_target_and_weapon_link_prefs();
5949 Game_mode |= GM_IN_MISSION;
5952 // required to truely make mouse deltas zeroed in debug mouse code
5953 void mouse_force_pos(int x, int y);
5954 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5959 // only start time if in single player, or coming from multi wait state
5962 (Game_mode & GM_NORMAL) &&
5963 (old_state != GS_STATE_VIEW_CUTSCENES)
5965 (Game_mode & GM_MULTIPLAYER) && (
5966 (old_state == GS_STATE_MULTI_PAUSED) ||
5967 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5973 // when coming from the multi paused state, reset the timestamps
5974 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5975 multi_reset_timestamps();
5978 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5979 // initialize all object update details
5980 multi_oo_gameplay_init();
5983 // under certain circumstances, the server should reset the object update rate limiting stuff
5984 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5985 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5987 // reinitialize the rate limiting system for all clients
5988 multi_oo_rate_init_all();
5991 // multiplayer clients should always re-initialize their control info rate limiting system
5992 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5993 multi_oo_rate_init_all();
5997 if(Game_mode & GM_MULTIPLAYER){
5998 multi_ping_reset_players();
6001 Game_subspace_effect = 0;
6002 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6003 Game_subspace_effect = 1;
6004 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6005 game_start_subspace_ambient_sound();
6009 sound_env_set(&Game_sound_env);
6010 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6012 // clear multiplayer button info i
6013 extern button_info Multi_ship_status_bi;
6014 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6017 case GS_STATE_HUD_CONFIG:
6021 case GS_STATE_MULTI_JOIN_GAME:
6022 multi_join_clear_game_list();
6024 if (old_state != GS_STATE_OPTIONS_MENU) {
6025 multi_join_game_init();
6030 case GS_STATE_MULTI_HOST_SETUP:
6031 // don't reinitialize if we're coming back from the host options screen
6032 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6033 multi_create_game_init();
6038 case GS_STATE_MULTI_CLIENT_SETUP:
6039 if (old_state != GS_STATE_OPTIONS_MENU) {
6040 multi_game_client_setup_init();
6045 case GS_STATE_CONTROL_CONFIG:
6046 control_config_init();
6049 case GS_STATE_TECH_MENU:
6053 case GS_STATE_BARRACKS_MENU:
6054 if(old_state != GS_STATE_VIEW_MEDALS){
6059 case GS_STATE_MISSION_LOG_SCROLLBACK:
6060 hud_scrollback_init();
6063 case GS_STATE_DEATH_DIED:
6064 Player_died_time = timestamp(10);
6066 if(!(Game_mode & GM_MULTIPLAYER)){
6067 player_show_death_message();
6069 Game_mode |= GM_DEAD_DIED;
6072 case GS_STATE_DEATH_BLEW_UP:
6073 if ( !popupdead_is_active() ) {
6074 Player_ai->target_objnum = -1;
6077 // stop any local EMP effect
6080 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6081 Game_mode |= GM_DEAD_BLEW_UP;
6082 Show_viewing_from_self = 0;
6084 // timestamp how long we should wait before displaying the died popup
6085 if ( !popupdead_is_active() ) {
6086 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6090 case GS_STATE_GAMEPLAY_HELP:
6091 gameplay_help_init();
6094 case GS_STATE_CREDITS:
6095 main_hall_stop_music();
6096 main_hall_stop_ambient();
6100 case GS_STATE_VIEW_MEDALS:
6101 medal_main_init(Player);
6104 case GS_STATE_SHOW_GOALS:
6105 mission_show_goals_init();
6108 case GS_STATE_HOTKEY_SCREEN:
6109 mission_hotkey_init();
6112 case GS_STATE_MULTI_MISSION_SYNC:
6113 // if we're coming from the options screen, don't do any
6114 if(old_state == GS_STATE_OPTIONS_MENU){
6118 switch(Multi_sync_mode){
6119 case MULTI_SYNC_PRE_BRIEFING:
6120 // if moving from game forming to the team select state
6123 case MULTI_SYNC_POST_BRIEFING:
6124 // if moving from briefing into the mission itself
6127 // tell everyone that we're now loading data
6128 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6129 send_netplayer_update_packet();
6131 // JAS: Used to do all paging here!!!!
6133 Net_player->state = NETPLAYER_STATE_WAITING;
6134 send_netplayer_update_packet();
6136 Game_time_compression = F1_0;
6138 case MULTI_SYNC_INGAME:
6144 case GS_STATE_VIEW_CUTSCENES:
6145 cutscenes_screen_init();
6148 case GS_STATE_MULTI_STD_WAIT:
6149 multi_standalone_wait_init();
6152 case GS_STATE_STANDALONE_MAIN:
6153 // don't initialize if we're coming from one of these 2 states unless there are no
6154 // players left (reset situation)
6155 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6156 standalone_main_init();
6160 case GS_STATE_MULTI_PAUSED:
6164 case GS_STATE_INGAME_PRE_JOIN:
6165 multi_ingame_select_init();
6168 case GS_STATE_STANDALONE_POSTGAME:
6169 multi_standalone_postgame_init();
6172 case GS_STATE_INITIAL_PLAYER_SELECT:
6173 player_select_init();
6176 case GS_STATE_MULTI_START_GAME:
6177 multi_start_game_init();
6180 case GS_STATE_MULTI_HOST_OPTIONS:
6181 multi_host_options_init();
6184 case GS_STATE_END_OF_CAMPAIGN:
6185 mission_campaign_end_init();
6188 case GS_STATE_LOOP_BRIEF:
6195 // do stuff that may need to be done regardless of state
6196 void game_do_state_common(int state,int no_networking)
6198 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6199 snd_do_frame(); // update sound system
6200 event_music_do_frame(); // music needs to play across many states
6202 multi_log_process();
6204 if (no_networking) {
6208 // maybe do a multiplayer frame based on game mode and state type
6209 if (Game_mode & GM_MULTIPLAYER) {
6211 case GS_STATE_OPTIONS_MENU:
6212 case GS_STATE_GAMEPLAY_HELP:
6213 case GS_STATE_HOTKEY_SCREEN:
6214 case GS_STATE_HUD_CONFIG:
6215 case GS_STATE_CONTROL_CONFIG:
6216 case GS_STATE_MISSION_LOG_SCROLLBACK:
6217 case GS_STATE_SHOW_GOALS:
6218 case GS_STATE_VIEW_CUTSCENES:
6219 case GS_STATE_EVENT_DEBUG:
6220 multi_maybe_do_frame();
6224 game_do_networking();
6228 // Called once a frame.
6229 // You should never try to change the state
6230 // in here... if you think you need to, you probably really
6231 // need to post an event, not change the state.
6232 int Game_do_state_should_skip = 0;
6233 void game_do_state(int state)
6235 // always lets the do_state_common() function determine if the state should be skipped
6236 Game_do_state_should_skip = 0;
6238 // legal to set the should skip state anywhere in this function
6239 game_do_state_common(state); // do stuff that may need to be done regardless of state
6241 if(Game_do_state_should_skip){
6246 case GS_STATE_MAIN_MENU:
6247 game_set_frametime(GS_STATE_MAIN_MENU);
6248 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6251 main_hall_do(flFrametime);
6255 case GS_STATE_OPTIONS_MENU:
6256 game_set_frametime(GS_STATE_OPTIONS_MENU);
6257 options_menu_do_frame(flFrametime);
6260 case GS_STATE_BARRACKS_MENU:
6261 game_set_frametime(GS_STATE_BARRACKS_MENU);
6262 barracks_do_frame(flFrametime);
6265 case GS_STATE_TRAINING_MENU:
6266 game_set_frametime(GS_STATE_TRAINING_MENU);
6267 training_menu_do_frame(flFrametime);
6270 case GS_STATE_TECH_MENU:
6271 game_set_frametime(GS_STATE_TECH_MENU);
6272 techroom_do_frame(flFrametime);
6275 case GS_STATE_GAMEPLAY_HELP:
6276 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6277 gameplay_help_do_frame(flFrametime);
6280 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6284 case GS_STATE_GAME_PAUSED:
6288 case GS_STATE_DEBUG_PAUSED:
6290 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6295 case GS_STATE_TRAINING_PAUSED:
6296 game_training_pause_do();
6299 case GS_STATE_LOAD_MISSION_MENU:
6300 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6301 mission_load_menu_do();
6304 case GS_STATE_BRIEFING:
6305 game_set_frametime(GS_STATE_BRIEFING);
6306 brief_do_frame(flFrametime);
6309 case GS_STATE_DEBRIEF:
6310 game_set_frametime(GS_STATE_DEBRIEF);
6311 debrief_do_frame(flFrametime);
6314 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6315 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6316 multi_df_debrief_do();
6319 case GS_STATE_SHIP_SELECT:
6320 game_set_frametime(GS_STATE_SHIP_SELECT);
6321 ship_select_do(flFrametime);
6324 case GS_STATE_WEAPON_SELECT:
6325 game_set_frametime(GS_STATE_WEAPON_SELECT);
6326 weapon_select_do(flFrametime);
6329 case GS_STATE_MISSION_LOG_SCROLLBACK:
6330 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6331 hud_scrollback_do_frame(flFrametime);
6334 case GS_STATE_HUD_CONFIG:
6335 game_set_frametime(GS_STATE_HUD_CONFIG);
6336 hud_config_do_frame(flFrametime);
6339 case GS_STATE_MULTI_JOIN_GAME:
6340 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6341 multi_join_game_do_frame();
6344 case GS_STATE_MULTI_HOST_SETUP:
6345 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6346 multi_create_game_do();
6349 case GS_STATE_MULTI_CLIENT_SETUP:
6350 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6351 multi_game_client_setup_do_frame();
6354 case GS_STATE_CONTROL_CONFIG:
6355 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6356 control_config_do_frame(flFrametime);
6359 case GS_STATE_DEATH_DIED:
6363 case GS_STATE_DEATH_BLEW_UP:
6367 case GS_STATE_SIMULATOR_ROOM:
6368 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6369 sim_room_do_frame(flFrametime);
6372 case GS_STATE_CAMPAIGN_ROOM:
6373 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6374 campaign_room_do_frame(flFrametime);
6377 case GS_STATE_RED_ALERT:
6378 game_set_frametime(GS_STATE_RED_ALERT);
6379 red_alert_do_frame(flFrametime);
6382 case GS_STATE_CMD_BRIEF:
6383 game_set_frametime(GS_STATE_CMD_BRIEF);
6384 cmd_brief_do_frame(flFrametime);
6387 case GS_STATE_CREDITS:
6388 game_set_frametime(GS_STATE_CREDITS);
6389 credits_do_frame(flFrametime);
6392 case GS_STATE_VIEW_MEDALS:
6393 game_set_frametime(GS_STATE_VIEW_MEDALS);
6397 case GS_STATE_SHOW_GOALS:
6398 game_set_frametime(GS_STATE_SHOW_GOALS);
6399 mission_show_goals_do_frame(flFrametime);
6402 case GS_STATE_HOTKEY_SCREEN:
6403 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6404 mission_hotkey_do_frame(flFrametime);
6407 case GS_STATE_VIEW_CUTSCENES:
6408 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6409 cutscenes_screen_do_frame();
6412 case GS_STATE_MULTI_STD_WAIT:
6413 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6414 multi_standalone_wait_do();
6417 case GS_STATE_STANDALONE_MAIN:
6418 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6419 standalone_main_do();
6422 case GS_STATE_MULTI_PAUSED:
6423 game_set_frametime(GS_STATE_MULTI_PAUSED);
6427 case GS_STATE_TEAM_SELECT:
6428 game_set_frametime(GS_STATE_TEAM_SELECT);
6432 case GS_STATE_INGAME_PRE_JOIN:
6433 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6434 multi_ingame_select_do();
6437 case GS_STATE_EVENT_DEBUG:
6439 game_set_frametime(GS_STATE_EVENT_DEBUG);
6440 game_show_event_debug(flFrametime);
6444 case GS_STATE_STANDALONE_POSTGAME:
6445 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6446 multi_standalone_postgame_do();
6449 case GS_STATE_INITIAL_PLAYER_SELECT:
6450 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6454 case GS_STATE_MULTI_MISSION_SYNC:
6455 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6459 case GS_STATE_MULTI_START_GAME:
6460 game_set_frametime(GS_STATE_MULTI_START_GAME);
6461 multi_start_game_do();
6464 case GS_STATE_MULTI_HOST_OPTIONS:
6465 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6466 multi_host_options_do();
6469 case GS_STATE_END_OF_CAMPAIGN:
6470 mission_campaign_end_do();
6473 case GS_STATE_END_DEMO:
6474 game_set_frametime(GS_STATE_END_DEMO);
6475 end_demo_campaign_do();
6478 case GS_STATE_LOOP_BRIEF:
6479 game_set_frametime(GS_STATE_LOOP_BRIEF);
6483 } // end switch(gs_current_state)
6487 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6488 int game_do_ram_check(int ram_in_bytes)
6490 if ( ram_in_bytes < 30*1024*1024 ) {
6491 int allowed_to_run = 1;
6492 if ( ram_in_bytes < 25*1024*1024 ) {
6497 int Freespace_total_ram_MB;
6498 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6500 if ( allowed_to_run ) {
6502 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);
6507 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6508 if ( msgbox_rval == IDCANCEL ) {
6515 sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run. If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE). Any memory allocated to SmartDrive is not usable by applications\n", 195), Freespace_total_ram_MB, Freespace_total_ram_MB);
6517 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6528 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6529 // If so, copy it over and remove the update directory.
6530 void game_maybe_update_launcher(char *exe_dir)
6533 char src_filename[MAX_PATH];
6534 char dest_filename[MAX_PATH];
6536 strcpy(src_filename, exe_dir);
6537 strcat(src_filename, NOX("\\update\\freespace.exe"));
6539 strcpy(dest_filename, exe_dir);
6540 strcat(dest_filename, NOX("\\freespace.exe"));
6542 // see if src_filename exists
6544 fp = fopen(src_filename, "rb");
6550 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6552 // copy updated freespace.exe to freespace exe dir
6553 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6554 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 );
6558 // delete the file in the update directory
6559 DeleteFile(src_filename);
6561 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6562 char update_dir[MAX_PATH];
6563 strcpy(update_dir, exe_dir);
6564 strcat(update_dir, NOX("\\update"));
6565 RemoveDirectory(update_dir);
6571 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6575 int sub_total_destroyed = 0;
6579 // get the total for all his children
6580 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6581 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6584 // find the # of faces for this _individual_ object
6585 total = submodel_get_num_polys(model_num, sm);
6586 if(strstr(pm->submodel[sm].name, "-destroyed")){
6587 sub_total_destroyed = total;
6591 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6594 *out_total += total + sub_total;
6595 *out_destroyed_total += sub_total_destroyed;
6598 #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);
6599 void game_spew_pof_info()
6601 char *pof_list[1000];
6604 int idx, model_num, i, j;
6606 int total, root_total, model_total, destroyed_total, counted;
6610 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6612 // spew info on all the pofs
6618 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6623 for(idx=0; idx<num_files; idx++, counted++){
6624 sprintf(str, "%s.pof", pof_list[idx]);
6625 model_num = model_load(str, 0, NULL);
6627 pm = model_get(model_num);
6629 // if we have a real model
6634 // go through and print all raw submodels
6635 cfputs("RAW\n", out);
6638 for (i=0; i<pm->n_models; i++) {
6639 total = submodel_get_num_polys(model_num, i);
6641 model_total += total;
6642 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6645 sprintf(str, "Model total %d\n", model_total);
6648 // now go through and do it by LOD
6649 cfputs("BY LOD\n\n", out);
6650 for(i=0; i<pm->n_detail_levels; i++){
6651 sprintf(str, "LOD %d\n", i);
6655 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6657 destroyed_total = 0;
6658 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6659 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6662 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6665 sprintf(str, "TOTAL: %d\n", total + root_total);
6667 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6669 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6672 cfputs("------------------------------------------------------------------------\n\n", out);
6676 if(counted >= MAX_POLYGON_MODELS - 5){
6689 game_spew_pof_info();
6692 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6697 // Don't let more than one instance of Freespace run.
6698 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6700 SetForegroundWindow(hwnd);
6705 // Find out how much RAM is on this machine
6708 ms.dwLength = sizeof(MEMORYSTATUS);
6709 GlobalMemoryStatus(&ms);
6710 Freespace_total_ram = ms.dwTotalPhys;
6712 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6716 if ( ms.dwTotalVirtual < 1024 ) {
6717 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6721 if (!vm_init(24*1024*1024)) {
6722 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 );
6726 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6728 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);
6738 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6739 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6740 seem worth bothering with.
6744 lResult = RegOpenKeyEx(
6745 HKEY_LOCAL_MACHINE, // Where it is
6746 "Software\\Microsoft\\DirectX", // name of key
6747 NULL, // DWORD reserved
6748 KEY_QUERY_VALUE, // Allows all changes
6749 &hKey // Location to store key
6752 if (lResult == ERROR_SUCCESS) {
6754 DWORD dwType, dwLen;
6757 lResult = RegQueryValueEx(
6758 hKey, // Handle to key
6759 "Version", // The values name
6760 NULL, // DWORD reserved
6761 &dwType, // What kind it is
6762 (ubyte *) version, // value to set
6763 &dwLen // How many bytes to set
6766 if (lResult == ERROR_SUCCESS) {
6767 dx_version = atoi(strstr(version, ".") + 1);
6771 DWORD dwType, dwLen;
6774 lResult = RegQueryValueEx(
6775 hKey, // Handle to key
6776 "InstalledVersion", // The values name
6777 NULL, // DWORD reserved
6778 &dwType, // What kind it is
6779 (ubyte *) &val, // value to set
6780 &dwLen // How many bytes to set
6783 if (lResult == ERROR_SUCCESS) {
6791 if (dx_version < 3) {
6792 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6793 "latest version of DirectX at:\n\n"
6794 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6796 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6797 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6802 //=====================================================
6803 // Make sure we're running in the right directory.
6807 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6808 char *p = exe_dir + strlen(exe_dir);
6810 // chop off the filename
6811 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6817 if ( strlen(exe_dir) > 0 ) {
6818 SetCurrentDirectory(exe_dir);
6821 // check for updated freespace.exe
6822 game_maybe_update_launcher(exe_dir);
6830 extern void windebug_memwatch_init();
6831 windebug_memwatch_init();
6835 parse_cmdline(szCmdLine);
6837 #ifdef STANDALONE_ONLY_BUILD
6839 nprintf(("Network", "Standalone running"));
6842 nprintf(("Network", "Standalone running"));
6850 // maybe spew pof stuff
6851 if(Cmdline_spew_pof_info){
6852 game_spew_pof_info();
6857 // non-demo, non-standalone, play the intro movie
6862 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) ){
6864 #if defined(OEM_BUILD)
6865 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6867 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6868 #endif // defined(OEM_BUILD)
6873 if ( !Is_standalone ) {
6875 // release -- movies always play
6878 // 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
6880 // movie_play( NOX("intro.mve"), 0 );
6882 // debug version, movie will only play with -showmovies
6883 #elif !defined(NDEBUG)
6886 // movie_play( NOX("intro.mve"), 0);
6889 if ( Cmdline_show_movies )
6890 movie_play( NOX("intro.mve"), 0 );
6899 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6901 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6905 // only important for non THREADED mode
6908 state = gameseq_process_events();
6909 if ( state == GS_STATE_QUIT_GAME ){
6916 demo_upsell_show_screens();
6918 #elif defined(OEM_BUILD)
6919 // show upsell screens on exit
6920 oem_upsell_show_screens();
6927 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6933 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6935 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6937 // Do nothing here - RecordExceptionInfo() has already done
6938 // everything that is needed. Actually this code won't even
6939 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6940 // the __except clause.
6946 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6947 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6953 // launcher the fslauncher program on exit
6954 void game_launch_launcher_on_exit()
6958 PROCESS_INFORMATION pi;
6959 char cmd_line[2048];
6960 char original_path[1024] = "";
6962 memset( &si, 0, sizeof(STARTUPINFO) );
6966 _getcwd(original_path, 1023);
6968 // set up command line
6969 strcpy(cmd_line, original_path);
6970 strcat(cmd_line, "\\");
6971 strcat(cmd_line, LAUNCHER_FNAME);
6972 strcat(cmd_line, " -straight_to_update");
6974 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6975 cmd_line, // pointer to command line string
6976 NULL, // pointer to process security attributes
6977 NULL, // pointer to thread security attributes
6978 FALSE, // handle inheritance flag
6979 CREATE_DEFAULT_ERROR_MODE, // creation flags
6980 NULL, // pointer to new environment block
6981 NULL, // pointer to current directory name
6982 &si, // pointer to STARTUPINFO
6983 &pi // pointer to PROCESS_INFORMATION
6985 // to eliminate build warnings
6995 // This function is called when FreeSpace terminates normally.
6997 void game_shutdown(void)
7003 // don't ever flip a page on the standalone!
7004 if(!(Game_mode & GM_STANDALONE_SERVER)){
7010 // if the player has left the "player select" screen and quit the game without actually choosing
7011 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7012 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7016 // load up common multiplayer icons
7017 multi_unload_common_icons();
7019 shockwave_close(); // release any memory used by shockwave system
7020 fireball_close(); // free fireball system
7021 ship_close(); // free any memory that was allocated for the ships
7022 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7023 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7024 bm_unload_all(); // free bitmaps
7025 mission_campaign_close(); // close out the campaign stuff
7026 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7028 #ifdef MULTI_USE_LAG
7032 // the menu close functions will unload the bitmaps if they were displayed during the game
7033 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7036 training_menu_close();
7039 extern void joy_close();
7042 audiostream_close();
7044 event_music_close();
7048 // HACKITY HACK HACK
7049 // if this flag is set, we should be firing up the launcher when exiting freespace
7050 extern int Multi_update_fireup_launcher_on_exit;
7051 if(Multi_update_fireup_launcher_on_exit){
7052 game_launch_launcher_on_exit();
7056 // game_stop_looped_sounds()
7058 // This function will call the appropriate stop looped sound functions for those
7059 // modules which use looping sounds. It is not enough just to stop a looping sound
7060 // at the DirectSound level, the game is keeping track of looping sounds, and this
7061 // function is used to inform the game that looping sounds are being halted.
7063 void game_stop_looped_sounds()
7065 hud_stop_looped_locking_sounds();
7066 hud_stop_looped_engine_sounds();
7067 afterburner_stop_sounds();
7068 player_stop_looped_sounds();
7069 obj_snd_stop_all(); // stop all object-linked persistant sounds
7070 game_stop_subspace_ambient_sound();
7071 snd_stop(Radar_static_looping);
7072 Radar_static_looping = -1;
7073 snd_stop(Target_static_looping);
7074 shipfx_stop_engine_wash_sound();
7075 Target_static_looping = -1;
7078 //////////////////////////////////////////////////////////////////////////
7080 // Code for supporting an animating mouse pointer
7083 //////////////////////////////////////////////////////////////////////////
7085 typedef struct animating_obj
7094 static animating_obj Animating_mouse;
7096 // ----------------------------------------------------------------------------
7097 // init_animating_pointer()
7099 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7100 // gets properly initialized
7102 void init_animating_pointer()
7104 Animating_mouse.first_frame = -1;
7105 Animating_mouse.num_frames = 0;
7106 Animating_mouse.current_frame = -1;
7107 Animating_mouse.time = 0.0f;
7108 Animating_mouse.elapsed_time = 0.0f;
7111 // ----------------------------------------------------------------------------
7112 // load_animating_pointer()
7114 // Called at game init to load in the frames for the animating mouse pointer
7116 // input: filename => filename of animation file that holds the animation
7118 void load_animating_pointer(char *filename, int dx, int dy)
7123 init_animating_pointer();
7125 am = &Animating_mouse;
7126 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7127 if ( am->first_frame == -1 )
7128 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7129 am->current_frame = 0;
7130 am->time = am->num_frames / i2fl(fps);
7133 // ----------------------------------------------------------------------------
7134 // unload_animating_pointer()
7136 // Called at game shutdown to free the memory used to store the animation frames
7138 void unload_animating_pointer()
7143 am = &Animating_mouse;
7144 for ( i = 0; i < am->num_frames; i++ ) {
7145 Assert( (am->first_frame+i) >= 0 );
7146 bm_release(am->first_frame + i);
7149 am->first_frame = -1;
7151 am->current_frame = -1;
7154 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7155 void game_render_mouse(float frametime)
7160 // if animating cursor exists, play the next frame
7161 am = &Animating_mouse;
7162 if ( am->first_frame != -1 ) {
7163 mouse_get_pos(&mx, &my);
7164 am->elapsed_time += frametime;
7165 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7166 if ( am->current_frame >= am->num_frames ) {
7167 am->current_frame = 0;
7168 am->elapsed_time = 0.0f;
7170 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7174 // ----------------------------------------------------------------------------
7175 // game_maybe_draw_mouse()
7177 // determines whether to draw the mouse pointer at all, and what frame of
7178 // animation to use if the mouse is animating
7180 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7182 // input: frametime => elapsed frame time in seconds since last call
7184 void game_maybe_draw_mouse(float frametime)
7188 game_state = gameseq_get_state();
7190 switch ( game_state ) {
7191 case GS_STATE_GAME_PAUSED:
7192 // case GS_STATE_MULTI_PAUSED:
7193 case GS_STATE_GAME_PLAY:
7194 case GS_STATE_DEATH_DIED:
7195 case GS_STATE_DEATH_BLEW_UP:
7196 if ( popup_active() || popupdead_is_active() ) {
7208 if ( !Mouse_hidden )
7209 game_render_mouse(frametime);
7213 void game_do_training_checks()
7217 waypoint_list *wplp;
7219 if (Training_context & TRAINING_CONTEXT_SPEED) {
7220 s = (int) Player_obj->phys_info.fspeed;
7221 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7222 if (!Training_context_speed_set) {
7223 Training_context_speed_set = 1;
7224 Training_context_speed_timestamp = timestamp();
7228 Training_context_speed_set = 0;
7231 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7232 wplp = &Waypoint_lists[Training_context_path];
7233 if (wplp->count > Training_context_goal_waypoint) {
7234 i = Training_context_goal_waypoint;
7236 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7237 if (d <= Training_context_distance) {
7238 Training_context_at_waypoint = i;
7239 if (Training_context_goal_waypoint == i) {
7240 Training_context_goal_waypoint++;
7241 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7248 if (i == wplp->count)
7251 } while (i != Training_context_goal_waypoint);
7255 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7256 Players_target = Player_ai->target_objnum;
7257 Players_targeted_subsys = Player_ai->targeted_subsys;
7258 Players_target_timestamp = timestamp();
7262 /////////// Following is for event debug view screen
7266 #define EVENT_DEBUG_MAX 5000
7267 #define EVENT_DEBUG_EVENT 0x8000
7269 int Event_debug_index[EVENT_DEBUG_MAX];
7272 void game_add_event_debug_index(int n, int indent)
7274 if (ED_count < EVENT_DEBUG_MAX)
7275 Event_debug_index[ED_count++] = n | (indent << 16);
7278 void game_add_event_debug_sexp(int n, int indent)
7283 if (Sexp_nodes[n].first >= 0) {
7284 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7285 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7289 game_add_event_debug_index(n, indent);
7290 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7291 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7293 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7296 void game_event_debug_init()
7301 for (e=0; e<Num_mission_events; e++) {
7302 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7303 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7307 void game_show_event_debug(float frametime)
7311 int font_height, font_width;
7313 static int scroll_offset = 0;
7315 k = game_check_key();
7321 if (scroll_offset < 0)
7331 scroll_offset -= 20;
7332 if (scroll_offset < 0)
7337 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7341 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7347 gr_set_color_fast(&Color_bright);
7349 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7351 gr_set_color_fast(&Color_normal);
7353 gr_get_string_size(&font_width, &font_height, NOX("test"));
7354 y_max = gr_screen.max_h - font_height - 5;
7358 while (k < ED_count) {
7359 if (y_index > y_max)
7362 z = Event_debug_index[k];
7363 if (z & EVENT_DEBUG_EVENT) {
7365 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7366 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7367 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7368 Mission_events[z].repeat_count, Mission_events[z].interval);
7376 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7377 switch (Sexp_nodes[z & 0x7fff].value) {
7379 strcat(buf, NOX(" (True)"));
7383 strcat(buf, NOX(" (False)"));
7386 case SEXP_KNOWN_TRUE:
7387 strcat(buf, NOX(" (Always true)"));
7390 case SEXP_KNOWN_FALSE:
7391 strcat(buf, NOX(" (Always false)"));
7394 case SEXP_CANT_EVAL:
7395 strcat(buf, NOX(" (Can't eval)"));
7399 case SEXP_NAN_FOREVER:
7400 strcat(buf, NOX(" (Not a number)"));
7405 gr_printf(10, y_index, buf);
7406 y_index += font_height;
7419 extern int Tmap_npixels;
7421 int Tmap_num_too_big = 0;
7422 int Num_models_needing_splitting = 0;
7424 void Time_model( int modelnum )
7426 // mprintf(( "Timing ship '%s'\n", si->name ));
7428 vector eye_pos, model_pos;
7429 matrix eye_orient, model_orient;
7431 polymodel *pm = model_get( modelnum );
7433 int l = strlen(pm->filename);
7435 if ( (l == '/') || (l=='\\') || (l==':')) {
7441 char *pof_file = &pm->filename[l];
7443 int model_needs_splitting = 0;
7445 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7447 for (i=0; i<pm->n_textures; i++ ) {
7448 char filename[1024];
7451 int bmp_num = pm->original_textures[i];
7452 if ( bmp_num > -1 ) {
7453 bm_get_palette(pm->original_textures[i], pal, filename );
7455 bm_get_info( pm->original_textures[i],&w, &h );
7458 if ( (w > 512) || (h > 512) ) {
7459 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7461 model_needs_splitting++;
7464 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7468 if ( model_needs_splitting ) {
7469 Num_models_needing_splitting++;
7471 eye_orient = model_orient = vmd_identity_matrix;
7472 eye_pos = model_pos = vmd_zero_vector;
7474 eye_pos.z = -pm->rad*2.0f;
7476 vector eye_to_model;
7478 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7479 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7481 fix t1 = timer_get_fixed_seconds();
7484 ta.p = ta.b = ta.h = 0.0f;
7489 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7491 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7493 modelstats_num_polys = modelstats_num_verts = 0;
7495 while( ta.h < PI2 ) {
7498 vm_angles_2_matrix(&m1, &ta );
7499 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7506 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7508 model_clear_instance( modelnum );
7509 model_set_detail_level(0); // use highest detail level
7510 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7518 int k = key_inkey();
7519 if ( k == KEY_ESC ) {
7524 fix t2 = timer_get_fixed_seconds();
7526 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7527 //bitmaps_used_this_frame /= framecount;
7529 modelstats_num_polys /= framecount;
7530 modelstats_num_verts /= framecount;
7532 Tmap_npixels /=framecount;
7535 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7536 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 );
7537 // 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 );
7543 int Time_models = 0;
7544 DCF_BOOL( time_models, Time_models );
7546 void Do_model_timings_test()
7550 if ( !Time_models ) return;
7552 mprintf(( "Timing models!\n" ));
7556 ubyte model_used[MAX_POLYGON_MODELS];
7557 int model_id[MAX_POLYGON_MODELS];
7558 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7563 for (i=0; i<Num_ship_types; i++ ) {
7564 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7566 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7567 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7570 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7571 if ( !Texture_fp ) return;
7573 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7574 if ( !Time_fp ) return;
7576 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7577 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7579 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7580 if ( model_used[i] ) {
7581 Time_model( model_id[i] );
7585 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7586 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7595 // Call this function when you want to inform the player that a feature is not
7596 // enabled in the DEMO version of FreSpace
7597 void game_feature_not_in_demo_popup()
7599 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7602 // format the specified time (fixed point) into a nice string
7603 void game_format_time(fix m_time,char *time_str)
7606 int hours,minutes,seconds;
7609 mtime = f2fl(m_time);
7611 // get the hours, minutes and seconds
7612 hours = (int)(mtime / 3600.0f);
7614 mtime -= (3600.0f * (float)hours);
7616 seconds = (int)mtime%60;
7617 minutes = (int)mtime/60;
7619 // print the hour if necessary
7621 sprintf(time_str,XSTR( "%d:", 201),hours);
7622 // if there are less than 10 minutes, print a leading 0
7624 strcpy(tmp,NOX("0"));
7625 strcat(time_str,tmp);
7629 // print the minutes
7631 sprintf(tmp,XSTR( "%d:", 201),minutes);
7632 strcat(time_str,tmp);
7634 sprintf(time_str,XSTR( "%d:", 201),minutes);
7637 // print the seconds
7639 strcpy(tmp,NOX("0"));
7640 strcat(time_str,tmp);
7642 sprintf(tmp,"%d",seconds);
7643 strcat(time_str,tmp);
7646 // Stuff version string in *str.
7647 void get_version_string(char *str)
7650 if ( FS_VERSION_BUILD == 0 ) {
7651 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7653 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7656 #if defined (FS2_DEMO)
7658 #elif defined (OEM_BUILD)
7659 strcat(str, " (OEM)");
7665 char myname[_MAX_PATH];
7666 int namelen, major, minor, build, waste;
7667 unsigned int buf_size;
7673 // Find my EXE file name
7674 hMod = GetModuleHandle(NULL);
7675 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7677 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7678 infop = (char *)malloc(version_size);
7679 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7681 // get the product version
7682 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7683 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7685 sprintf(str,"Dv%d.%02d",major, minor);
7687 sprintf(str,"v%d.%02d",major, minor);
7692 void get_version_string_short(char *str)
7694 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7697 // ----------------------------------------------------------------
7699 // OEM UPSELL SCREENS BEGIN
7701 // ----------------------------------------------------------------
7702 #if defined(OEM_BUILD)
7704 #define NUM_OEM_UPSELL_SCREENS 3
7705 #define OEM_UPSELL_SCREEN_DELAY 10000
7707 static int Oem_upsell_bitmaps_loaded = 0;
7708 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7709 static int Oem_upsell_screen_number = 0;
7710 static int Oem_upsell_show_next_bitmap_time;
7713 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7726 static int Oem_normal_cursor = -1;
7727 static int Oem_web_cursor = -1;
7728 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7729 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7731 void oem_upsell_next_screen()
7733 Oem_upsell_screen_number++;
7734 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7735 // extra long delay, mouse shown on last upsell
7736 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7740 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7744 void oem_upsell_load_bitmaps()
7748 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7749 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7753 void oem_upsell_unload_bitmaps()
7757 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7758 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7759 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7764 Oem_upsell_bitmaps_loaded = 0;
7767 // clickable hotspot on 3rd OEM upsell screen
7768 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7770 28, 350, 287, 96 // x, y, w, h
7773 45, 561, 460, 152 // x, y, w, h
7777 void oem_upsell_show_screens()
7779 int current_time, k;
7782 if ( !Oem_upsell_bitmaps_loaded ) {
7783 oem_upsell_load_bitmaps();
7784 Oem_upsell_bitmaps_loaded = 1;
7787 // may use upsell screens more than once
7788 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7789 Oem_upsell_screen_number = 0;
7795 int nframes; // used to pass, not really needed (should be 1)
7796 Oem_normal_cursor = gr_get_cursor_bitmap();
7797 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7798 Assert(Oem_web_cursor >= 0);
7799 if (Oem_web_cursor < 0) {
7800 Oem_web_cursor = Oem_normal_cursor;
7805 //oem_reset_trailer_timer();
7807 current_time = timer_get_milliseconds();
7812 // advance screen on keypress or timeout
7813 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7814 oem_upsell_next_screen();
7817 // check if we are done
7818 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7819 Oem_upsell_screen_number--;
7822 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7827 // show me the upsell
7828 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7829 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7833 // if this is the 3rd upsell, make it clickable, d00d
7834 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7836 int button_state = mouse_get_pos(&mx, &my);
7837 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])
7838 && (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]) )
7841 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7844 if (button_state & MOUSE_LEFT_BUTTON) {
7846 multi_pxo_url(OEM_UPSELL_URL);
7850 // switch cursor back to normal one
7851 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7856 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7866 oem_upsell_unload_bitmaps();
7868 // switch cursor back to normal one
7869 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7873 #endif // defined(OEM_BUILD)
7874 // ----------------------------------------------------------------
7876 // OEM UPSELL SCREENS END
7878 // ----------------------------------------------------------------
7882 // ----------------------------------------------------------------
7884 // DEMO UPSELL SCREENS BEGIN
7886 // ----------------------------------------------------------------
7890 //#define NUM_DEMO_UPSELL_SCREENS 4
7892 #define NUM_DEMO_UPSELL_SCREENS 2
7893 #define DEMO_UPSELL_SCREEN_DELAY 3000
7895 static int Demo_upsell_bitmaps_loaded = 0;
7896 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7897 static int Demo_upsell_screen_number = 0;
7898 static int Demo_upsell_show_next_bitmap_time;
7901 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7914 void demo_upsell_next_screen()
7916 Demo_upsell_screen_number++;
7917 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7918 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7920 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7924 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7925 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7926 #ifndef HARDWARE_ONLY
7927 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7934 void demo_upsell_load_bitmaps()
7938 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7939 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7943 void demo_upsell_unload_bitmaps()
7947 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7948 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7949 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7954 Demo_upsell_bitmaps_loaded = 0;
7957 void demo_upsell_show_screens()
7959 int current_time, k;
7962 if ( !Demo_upsell_bitmaps_loaded ) {
7963 demo_upsell_load_bitmaps();
7964 Demo_upsell_bitmaps_loaded = 1;
7967 // may use upsell screens more than once
7968 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7969 Demo_upsell_screen_number = 0;
7976 demo_reset_trailer_timer();
7978 current_time = timer_get_milliseconds();
7985 // don't time out, wait for keypress
7987 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7988 demo_upsell_next_screen();
7993 demo_upsell_next_screen();
7996 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7997 Demo_upsell_screen_number--;
8000 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8005 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8006 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8011 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8021 demo_upsell_unload_bitmaps();
8026 // ----------------------------------------------------------------
8028 // DEMO UPSELL SCREENS END
8030 // ----------------------------------------------------------------
8033 // ----------------------------------------------------------------
8035 // Subspace Ambient Sound START
8037 // ----------------------------------------------------------------
8039 static int Subspace_ambient_left_channel = -1;
8040 static int Subspace_ambient_right_channel = -1;
8043 void game_start_subspace_ambient_sound()
8045 if ( Subspace_ambient_left_channel < 0 ) {
8046 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8049 if ( Subspace_ambient_right_channel < 0 ) {
8050 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8054 void game_stop_subspace_ambient_sound()
8056 if ( Subspace_ambient_left_channel >= 0 ) {
8057 snd_stop(Subspace_ambient_left_channel);
8058 Subspace_ambient_left_channel = -1;
8061 if ( Subspace_ambient_right_channel >= 0 ) {
8062 snd_stop(Subspace_ambient_right_channel);
8063 Subspace_ambient_right_channel = -1;
8067 // ----------------------------------------------------------------
8069 // Subspace Ambient Sound END
8071 // ----------------------------------------------------------------
8073 // ----------------------------------------------------------------
8075 // CDROM detection code START
8077 // ----------------------------------------------------------------
8079 #define CD_SIZE_72_MINUTE_MAX (697000000)
8081 uint game_get_cd_used_space(char *path)
8085 char use_path[512] = "";
8086 char sub_path[512] = "";
8087 WIN32_FIND_DATA find;
8090 // recurse through all files and directories
8091 strcpy(use_path, path);
8092 strcat(use_path, "*.*");
8093 find_handle = FindFirstFile(use_path, &find);
8096 if(find_handle == INVALID_HANDLE_VALUE){
8102 // subdirectory. make sure to ignore . and ..
8103 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8105 strcpy(sub_path, path);
8106 strcat(sub_path, find.cFileName);
8107 strcat(sub_path, "\\");
8108 total += game_get_cd_used_space(sub_path);
8110 total += (uint)find.nFileSizeLow;
8112 } while(FindNextFile(find_handle, &find));
8115 FindClose(find_handle);
8127 // if volume_name is non-null, the CD name must match that
8128 int find_freespace_cd(char *volume_name)
8131 char oldpath[MAX_PATH];
8135 int volume_match = 0;
8139 GetCurrentDirectory(MAX_PATH, oldpath);
8141 for (i = 0; i < 26; i++)
8147 path[0] = (char)('A'+i);
8148 if (GetDriveType(path) == DRIVE_CDROM) {
8150 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8151 nprintf(("CD", "CD volume: %s\n", volume));
8153 // check for any CD volume
8154 int volume1_present = 0;
8155 int volume2_present = 0;
8156 int volume3_present = 0;
8158 char full_check[512] = "";
8160 // look for setup.exe
8161 strcpy(full_check, path);
8162 strcat(full_check, "setup.exe");
8163 find_handle = _findfirst(full_check, &find);
8164 if(find_handle != -1){
8165 volume1_present = 1;
8166 _findclose(find_handle);
8169 // look for intro.mve
8170 strcpy(full_check, path);
8171 strcat(full_check, "intro.mve");
8172 find_handle = _findfirst(full_check, &find);
8173 if(find_handle != -1){
8174 volume2_present = 1;
8175 _findclose(find_handle);
8178 // look for endpart1.mve
8179 strcpy(full_check, path);
8180 strcat(full_check, "endpart1.mve");
8181 find_handle = _findfirst(full_check, &find);
8182 if(find_handle != -1){
8183 volume3_present = 1;
8184 _findclose(find_handle);
8187 // see if we have the specific CD we're looking for
8188 if ( volume_name ) {
8190 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8194 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8198 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8202 if ( volume1_present || volume2_present || volume3_present ) {
8207 // 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
8208 if ( volume_match ){
8210 // 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
8211 if(volume2_present || volume3_present) {
8212 // first step - check to make sure its a cdrom
8213 if(GetDriveType(path) != DRIVE_CDROM){
8217 #if !defined(OEM_BUILD)
8218 // oem not on 80 min cds, so dont check tha size
8220 uint used_space = game_get_cd_used_space(path);
8221 if(used_space < CD_SIZE_72_MINUTE_MAX){
8224 #endif // !defined(OEM_BUILD)
8232 #endif // RELEASE_REAL
8238 SetCurrentDirectory(oldpath);
8247 int set_cdrom_path(int drive_num)
8251 if (drive_num < 0) { //no CD
8253 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8256 strcpy(Game_CDROM_dir,""); //set directory
8260 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8276 i = find_freespace_cd();
8278 rval = set_cdrom_path(i);
8282 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8284 nprintf(("CD", "FreeSpace CD not found\n"));
8292 int Last_cd_label_found = 0;
8293 char Last_cd_label[256];
8295 int game_cd_changed()
8302 if ( strlen(Game_CDROM_dir) == 0 ) {
8306 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8308 if ( found != Last_cd_label_found ) {
8309 Last_cd_label_found = found;
8311 mprintf(( "CD '%s' was inserted\n", label ));
8314 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8318 if ( Last_cd_label_found ) {
8319 if ( !stricmp( Last_cd_label, label )) {
8320 //mprintf(( "CD didn't change\n" ));
8322 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8326 // none found before, none found now.
8327 //mprintf(( "still no CD...\n" ));
8331 Last_cd_label_found = found;
8333 strcpy( Last_cd_label, label );
8335 strcpy( Last_cd_label, "" );
8346 // check if _any_ FreeSpace2 CDs are in the drive
8347 // return: 1 => CD now in drive
8348 // 0 => Could not find CD, they refuse to put it in the drive
8349 int game_do_cd_check(char *volume_name)
8351 #if !defined(GAME_CD_CHECK)
8357 int num_attempts = 0;
8358 int refresh_files = 0;
8360 int path_set_ok, popup_rval;
8362 cd_drive_num = find_freespace_cd(volume_name);
8363 path_set_ok = set_cdrom_path(cd_drive_num);
8364 if ( path_set_ok ) {
8366 if ( refresh_files ) {
8378 // no CD found, so prompt user
8379 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8381 if ( popup_rval != 1 ) {
8386 if ( num_attempts++ > 5 ) {
8397 // check if _any_ FreeSpace2 CDs are in the drive
8398 // return: 1 => CD now in drive
8399 // 0 => Could not find CD, they refuse to put it in the drive
8400 int game_do_cd_check_specific(char *volume_name, int cdnum)
8405 int num_attempts = 0;
8406 int refresh_files = 0;
8408 int path_set_ok, popup_rval;
8410 cd_drive_num = find_freespace_cd(volume_name);
8411 path_set_ok = set_cdrom_path(cd_drive_num);
8412 if ( path_set_ok ) {
8414 if ( refresh_files ) {
8425 // no CD found, so prompt user
8426 #if defined(DVD_MESSAGE_HACK)
8427 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8429 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8432 if ( popup_rval != 1 ) {
8437 if ( num_attempts++ > 5 ) {
8447 // only need to do this in RELEASE_REAL
8448 int game_do_cd_mission_check(char *filename)
8454 fs_builtin_mission *m = game_find_builtin_mission(filename);
8456 // check for changed CD
8457 if(game_cd_changed()){
8462 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8466 // not builtin, so do a general check (any FS2 CD will do)
8468 return game_do_cd_check();
8471 // does not have any CD requirement, do a general check
8472 if(strlen(m->cd_volume) <= 0){
8473 return game_do_cd_check();
8477 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8479 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8481 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8484 return game_do_cd_check();
8487 // did we find the cd?
8488 if(find_freespace_cd(m->cd_volume) >= 0){
8492 // make sure the volume exists
8493 int num_attempts = 0;
8494 int refresh_files = 0;
8496 int path_set_ok, popup_rval;
8498 cd_drive_num = find_freespace_cd(m->cd_volume);
8499 path_set_ok = set_cdrom_path(cd_drive_num);
8500 if ( path_set_ok ) {
8502 if ( refresh_files ) {
8509 // no CD found, so prompt user
8510 #if defined(DVD_MESSAGE_HACK)
8511 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8513 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8517 if ( popup_rval != 1 ) {
8522 if ( num_attempts++ > 5 ) {
8534 // ----------------------------------------------------------------
8536 // CDROM detection code END
8538 // ----------------------------------------------------------------
8540 // ----------------------------------------------------------------
8541 // SHIPS TBL VERIFICATION STUFF
8544 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8545 #define NUM_SHIPS_TBL_CHECKSUMS 1
8547 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8548 -463907578, // US - beta 1
8549 1696074201, // FS2 demo
8552 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8553 // -1022810006, // 1.0 FULL
8554 -1254285366 // 1.2 FULL (German)
8557 void verify_ships_tbl()
8561 Game_ships_tbl_valid = 1;
8567 // detect if the packfile exists
8568 CFILE *detect = cfopen("ships.tbl", "rb");
8569 Game_ships_tbl_valid = 0;
8573 Game_ships_tbl_valid = 0;
8577 // get the long checksum of the file
8579 cfseek(detect, 0, SEEK_SET);
8580 cf_chksum_long(detect, &file_checksum);
8584 // now compare the checksum/filesize against known #'s
8585 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8586 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8587 Game_ships_tbl_valid = 1;
8594 DCF(shipspew, "display the checksum for the current ships.tbl")
8597 CFILE *detect = cfopen("ships.tbl", "rb");
8598 // get the long checksum of the file
8600 cfseek(detect, 0, SEEK_SET);
8601 cf_chksum_long(detect, &file_checksum);
8604 dc_printf("%d", file_checksum);
8607 // ----------------------------------------------------------------
8608 // WEAPONS TBL VERIFICATION STUFF
8611 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8612 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8614 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8615 141718090, // US - beta 1
8616 -266420030, // demo 1
8619 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8620 // 399297860, // 1.0 FULL
8621 -553984927 // 1.2 FULL (german)
8624 void verify_weapons_tbl()
8628 Game_weapons_tbl_valid = 1;
8634 // detect if the packfile exists
8635 CFILE *detect = cfopen("weapons.tbl", "rb");
8636 Game_weapons_tbl_valid = 0;
8640 Game_weapons_tbl_valid = 0;
8644 // get the long checksum of the file
8646 cfseek(detect, 0, SEEK_SET);
8647 cf_chksum_long(detect, &file_checksum);
8651 // now compare the checksum/filesize against known #'s
8652 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8653 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8654 Game_weapons_tbl_valid = 1;
8661 DCF(wepspew, "display the checksum for the current weapons.tbl")
8664 CFILE *detect = cfopen("weapons.tbl", "rb");
8665 // get the long checksum of the file
8667 cfseek(detect, 0, SEEK_SET);
8668 cf_chksum_long(detect, &file_checksum);
8671 dc_printf("%d", file_checksum);
8674 // if the game is running using hacked data
8675 int game_hacked_data()
8678 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8686 void display_title_screen()
8688 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8689 ///int title_bitmap;
8692 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8693 if (title_bitmap == -1) {
8699 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8700 extern void d3d_start_frame();
8706 gr_set_bitmap(title_bitmap);
8713 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8714 extern void d3d_stop_frame();
8722 bm_unload(title_bitmap);
8723 #endif // FS2_DEMO || OEM_BUILD
8726 // return true if the game is running with "low memory", which is less than 48MB
8727 bool game_using_low_mem()
8729 if (Use_low_mem == 0) {