2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.10 2002/06/01 07:12:32 relnev
11 * a few NDEBUG updates.
13 * removed a few warnings.
15 * Revision 1.9 2002/05/31 03:05:59 relnev
18 * Revision 1.8 2002/05/29 02:52:32 theoddone33
19 * Enable OpenGL renderer
21 * Revision 1.7 2002/05/28 08:52:03 relnev
22 * implemented two assembly stubs.
24 * cleaned up a few warnings.
26 * added a little demo hackery to make it progress a little farther.
28 * Revision 1.6 2002/05/28 06:28:20 theoddone33
29 * Filesystem mods, actually reads some data files now
31 * Revision 1.5 2002/05/28 04:07:28 theoddone33
32 * New graphics stubbing arrangement
34 * Revision 1.4 2002/05/27 22:46:52 theoddone33
35 * Remove more undefined symbols
37 * Revision 1.3 2002/05/26 23:31:18 relnev
38 * added a few files that needed to be compiled
40 * freespace.cpp: now compiles
42 * Revision 1.2 2002/05/07 03:16:44 theoddone33
43 * The Great Newline Fix
45 * Revision 1.1.1.1 2002/05/03 03:28:09 root
49 * 201 6/16/00 3:15p Jefff
50 * sim of the year dvd version changes, a few german soty localization
53 * 200 11/03/99 11:06a Jefff
56 * 199 10/26/99 5:07p Jamest
57 * fixed jeffs dumb debug code
59 * 198 10/25/99 5:53p Jefff
60 * call control_config_common_init() on startup
62 * 197 10/14/99 10:18a Daveb
63 * Fixed incorrect CD checking problem on standalone server.
65 * 196 10/13/99 9:22a Daveb
66 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
67 * related to movies. Fixed launcher spawning from PXO screen.
69 * 195 10/06/99 11:05a Jefff
70 * new oem upsell 3 hotspot coords
72 * 194 10/06/99 10:31a Jefff
75 * 193 10/01/99 9:10a Daveb
78 * 192 9/15/99 4:57a Dave
79 * Updated ships.tbl checksum
81 * 191 9/15/99 3:58a Dave
82 * Removed framerate warning at all times.
84 * 190 9/15/99 3:16a Dave
85 * Remove mt-011.fs2 from the builtin mission list.
87 * 189 9/15/99 1:45a Dave
88 * Don't init joystick on standalone. Fixed campaign mode on standalone.
89 * Fixed no-score-report problem in TvT
91 * 188 9/14/99 6:08a Dave
92 * Updated (final) single, multi, and campaign list.
94 * 187 9/14/99 3:26a Dave
95 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
96 * respawn-too-early problem. Made a few crash points safe.
98 * 186 9/13/99 4:52p Dave
101 * 185 9/12/99 8:09p Dave
102 * Fixed problem where skip-training button would cause mission messages
103 * not to get paged out for the current mission.
105 * 184 9/10/99 11:53a Dave
106 * Shutdown graphics before sound to eliminate apparent lockups when
107 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
109 * 183 9/09/99 11:40p Dave
110 * Handle an Assert() in beam code. Added supernova sounds. Play the right
111 * 2 end movies properly, based upon what the player did in the mission.
113 * 182 9/08/99 10:29p Dave
114 * Make beam sound pausing and unpausing much safer.
116 * 181 9/08/99 10:01p Dave
117 * Make sure game won't run in a drive's root directory. Make sure
118 * standalone routes suqad war messages properly to the host.
120 * 180 9/08/99 3:22p Dave
121 * Updated builtin mission list.
123 * 179 9/08/99 12:01p Jefff
124 * fixed Game_builtin_mission_list typo on Training-2.fs2
126 * 178 9/08/99 9:48a Andsager
127 * Add force feedback for engine wash.
129 * 177 9/07/99 4:01p Dave
130 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
131 * does everything properly (setting up address when binding). Remove
132 * black rectangle background from UI_INPUTBOX.
134 * 176 9/13/99 2:40a Dave
135 * Comment in full 80 minute CD check for RELEASE_REAL builds.
137 * 175 9/06/99 6:38p Dave
138 * Improved CD detection code.
140 * 174 9/06/99 1:30a Dave
141 * Intermediate checkin. Started on enforcing CD-in-drive to play the
144 * 173 9/06/99 1:16a Dave
145 * Make sure the user sees the intro movie.
147 * 172 9/04/99 8:00p Dave
148 * Fixed up 1024 and 32 bit movie support.
150 * 171 9/03/99 1:32a Dave
151 * CD checking by act. Added support to play 2 cutscenes in a row
152 * seamlessly. Fixed super low level cfile bug related to files in the
153 * root directory of a CD. Added cheat code to set campaign mission # in
156 * 170 9/01/99 10:49p Dave
157 * Added nice SquadWar checkbox to the client join wait screen.
159 * 169 9/01/99 10:14a Dave
162 * 168 8/29/99 4:51p Dave
163 * Fixed damaged checkin.
165 * 167 8/29/99 4:18p Andsager
166 * New "burst" limit for friendly damage. Also credit more damage done
167 * against large friendly ships.
169 * 166 8/27/99 6:38p Alanl
170 * crush the blasted repeating messages bug
172 * 164 8/26/99 9:09p Dave
173 * Force framerate check in everything but a RELEASE_REAL build.
175 * 163 8/26/99 9:45a Dave
176 * First pass at easter eggs and cheats.
178 * 162 8/24/99 8:55p Dave
179 * Make sure nondimming pixels work properly in tech menu.
181 * 161 8/24/99 1:49a Dave
182 * Fixed client-side afterburner stuttering. Added checkbox for no version
183 * checking on PXO join. Made button info passing more friendly between
186 * 160 8/22/99 5:53p Dave
187 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
188 * instead of ship designations for multiplayer players.
190 * 159 8/22/99 1:19p Dave
191 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
192 * which d3d cards are detected.
194 * 158 8/20/99 2:09p Dave
195 * PXO banner cycling.
197 * 157 8/19/99 10:59a Dave
198 * Packet loss detection.
200 * 156 8/19/99 10:12a Alanl
201 * preload mission-specific messages on machines greater than 48MB
203 * 155 8/16/99 4:04p Dave
204 * Big honking checkin.
206 * 154 8/11/99 5:54p Dave
207 * Fixed collision problem. Fixed standalone ghost problem.
209 * 153 8/10/99 7:59p Jefff
212 * 152 8/10/99 6:54p Dave
213 * Mad optimizations. Added paging to the nebula effect.
215 * 151 8/10/99 3:44p Jefff
216 * loads Intelligence information on startup
218 * 150 8/09/99 3:47p Dave
219 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
220 * non-nebula missions.
222 * 149 8/09/99 2:21p Andsager
223 * Fix patching from multiplayer direct to launcher update tab.
225 * 148 8/09/99 10:36a Dave
226 * Version info for game.
228 * 147 8/06/99 9:46p Dave
229 * Hopefully final changes for the demo.
231 * 146 8/06/99 3:34p Andsager
232 * Make title version info "(D)" -> "D" show up nicely
234 * 145 8/06/99 2:59p Adamp
235 * Fixed NT launcher/update problem.
237 * 144 8/06/99 1:52p Dave
238 * Bumped up MAX_BITMAPS for the demo.
240 * 143 8/06/99 12:17p Andsager
241 * Demo: down to just 1 demo dog
243 * 142 8/05/99 9:39p Dave
244 * Yet another new checksum.
246 * 141 8/05/99 6:19p Dave
247 * New demo checksums.
249 * 140 8/05/99 5:31p Andsager
250 * Up demo version 1.01
252 * 139 8/05/99 4:22p Andsager
253 * No time limit on upsell screens. Reverse order of display of upsell
256 * 138 8/05/99 4:17p Dave
257 * Tweaks to client interpolation.
259 * 137 8/05/99 3:52p Danw
261 * 136 8/05/99 3:01p Danw
263 * 135 8/05/99 2:43a Anoop
264 * removed duplicate definition.
266 * 134 8/05/99 2:13a Dave
269 * 133 8/05/99 2:05a Dave
272 * 132 8/05/99 1:22a Andsager
275 * 131 8/04/99 9:51p Andsager
276 * Add title screen to demo
278 * 130 8/04/99 6:47p Jefff
279 * fixed link error resulting from #ifdefs
281 * 129 8/04/99 6:26p Dave
282 * Updated ship tbl checksum.
284 * 128 8/04/99 5:40p Andsager
285 * Add multiple demo dogs
287 * 127 8/04/99 5:36p Andsager
288 * Show upsell screens at end of demo campaign before returning to main
291 * 126 8/04/99 11:42a Danw
292 * tone down EAX reverb
294 * 125 8/04/99 11:23a Dave
295 * Updated demo checksums.
297 * 124 8/03/99 11:02p Dave
298 * Maybe fixed sync problems in multiplayer.
300 * 123 8/03/99 6:21p Jefff
303 * 122 8/03/99 3:44p Andsager
304 * Launch laucher if trying to run FS without first having configured
307 * 121 8/03/99 12:45p Dave
310 * 120 8/02/99 9:13p Dave
313 * 119 7/30/99 10:31p Dave
314 * Added comm menu to the configurable hud files.
316 * 118 7/30/99 5:17p Andsager
317 * first fs2demo checksums
319 * 117 7/29/99 3:09p Anoop
321 * 116 7/29/99 12:05a Dave
322 * Nebula speed optimizations.
324 * 115 7/27/99 8:59a Andsager
325 * Make major, minor version consistent for all builds. Only show major
326 * and minor for launcher update window.
328 * 114 7/26/99 5:50p Dave
329 * Revised ingame join. Better? We'll see....
331 * 113 7/26/99 5:27p Andsager
332 * Add training mission as builtin to demo build
334 * 112 7/24/99 1:54p Dave
335 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
338 * 111 7/22/99 4:00p Dave
339 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
341 * 110 7/21/99 8:10p Dave
342 * First run of supernova effect.
344 * 109 7/20/99 1:49p Dave
345 * Peter Drake build. Fixed some release build warnings.
347 * 108 7/19/99 2:26p Andsager
348 * set demo multiplayer missions
350 * 107 7/18/99 5:19p Dave
351 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
353 * 106 7/16/99 1:50p Dave
354 * 8 bit aabitmaps. yay.
356 * 105 7/15/99 3:07p Dave
357 * 32 bit detection support. Mouse coord commandline.
359 * 104 7/15/99 2:13p Dave
360 * Added 32 bit detection.
362 * 103 7/15/99 9:20a Andsager
363 * FS2_DEMO initial checkin
365 * 102 7/14/99 11:02a Dave
366 * Skill level default back to easy. Blech.
368 * 101 7/09/99 5:54p Dave
369 * Seperated cruiser types into individual types. Added tons of new
370 * briefing icons. Campaign screen.
372 * 100 7/08/99 4:43p Andsager
373 * New check for sparky_hi and print if not found.
375 * 99 7/08/99 10:53a Dave
376 * New multiplayer interpolation scheme. Not 100% done yet, but still
377 * better than the old way.
379 * 98 7/06/99 4:24p Dave
380 * Mid-level checkin. Starting on some potentially cool multiplayer
383 * 97 7/06/99 3:35p Andsager
384 * Allow movie to play before red alert mission.
386 * 96 7/03/99 5:50p Dave
387 * Make rotated bitmaps draw properly in padlock views.
389 * 95 7/02/99 9:55p Dave
390 * Player engine wash sound.
392 * 94 7/02/99 4:30p Dave
393 * Much more sophisticated lightning support.
395 * 93 6/29/99 7:52p Dave
396 * Put in exception handling in FS2.
398 * 92 6/22/99 9:37p Dave
399 * Put in pof spewing.
401 * 91 6/16/99 4:06p Dave
402 * New pilot info popup. Added new draw-bitmap-as-poly function.
404 * 90 6/15/99 1:56p Andsager
405 * For release builds, allow start up in high res only with
408 * 89 6/15/99 9:34a Dave
409 * Fixed key checking in single threaded version of the stamp notification
412 * 88 6/09/99 2:55p Andsager
413 * Allow multiple asteroid subtypes (of large, medium, small) and follow
416 * 87 6/08/99 1:14a Dave
417 * Multi colored hud test.
419 * 86 6/04/99 9:52a Dave
420 * Fixed some rendering problems.
422 * 85 6/03/99 10:15p Dave
423 * Put in temporary main hall screen.
425 * 84 6/02/99 6:18p Dave
426 * Fixed TNT lockup problems! Wheeeee!
428 * 83 6/01/99 3:52p Dave
429 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
430 * dead popup, pxo find player popup, pxo private room popup.
432 * 82 5/26/99 1:28p Jasenw
433 * changed coords for loading ani
435 * 81 5/26/99 11:46a Dave
436 * Added ship-blasting lighting and made the randomization of lighting
437 * much more customizable.
439 * 80 5/24/99 5:45p Dave
440 * Added detail levels to the nebula, with a decent speedup. Split nebula
441 * lightning into its own section.
459 #include "systemvars.h"
464 #include "starfield.h"
465 #include "lighting.h"
470 #include "fireballs.h"
474 #include "floating.h"
475 #include "gamesequence.h"
477 #include "optionsmenu.h"
478 #include "playermenu.h"
479 #include "trainingmenu.h"
480 #include "techmenu.h"
483 #include "hudmessage.h"
485 #include "missiongoals.h"
486 #include "missionparse.h"
491 #include "multiutil.h"
492 #include "multimsgs.h"
496 #include "freespace.h"
497 #include "managepilot.h"
499 #include "contexthelp.h"
502 #include "missionbrief.h"
503 #include "missiondebrief.h"
505 #include "missionshipchoice.h"
507 #include "hudconfig.h"
508 #include "controlsconfig.h"
509 #include "missionmessage.h"
510 #include "missiontraining.h"
512 #include "hudtarget.h"
516 #include "eventmusic.h"
517 #include "animplay.h"
518 #include "missionweaponchoice.h"
519 #include "missionlog.h"
520 #include "audiostr.h"
522 #include "missioncampaign.h"
524 #include "missionhotkey.h"
525 #include "objectsnd.h"
526 #include "cmeasure.h"
528 #include "linklist.h"
529 #include "shockwave.h"
530 #include "afterburner.h"
535 #include "stand_gui.h"
536 #include "pcxutils.h"
537 #include "hudtargetbox.h"
538 #include "multi_xfer.h"
539 #include "hudescort.h"
540 #include "multiutil.h"
543 #include "multiteamselect.h"
546 #include "readyroom.h"
547 #include "mainhallmenu.h"
548 #include "multilag.h"
550 #include "particle.h"
552 #include "multi_ingame.h"
553 #include "snazzyui.h"
554 #include "asteroid.h"
555 #include "popupdead.h"
556 #include "multi_voice.h"
557 #include "missioncmdbrief.h"
558 #include "redalert.h"
559 #include "gameplayhelp.h"
560 #include "multilag.h"
561 #include "staticrand.h"
562 #include "multi_pmsg.h"
563 #include "levelpaging.h"
564 #include "observer.h"
565 #include "multi_pause.h"
566 #include "multi_endgame.h"
567 #include "cutscenes.h"
568 #include "multi_respawn.h"
569 // #include "movie.h"
570 #include "multi_obj.h"
571 #include "multi_log.h"
573 #include "localize.h"
574 #include "osregistry.h"
575 #include "barracks.h"
576 #include "missionpause.h"
578 #include "alphacolors.h"
579 #include "objcollide.h"
582 #include "neblightning.h"
583 #include "shipcontrails.h"
586 #include "multi_dogfight.h"
587 #include "multi_rate.h"
588 #include "muzzleflash.h"
592 #include "mainhalltemp.h"
593 #include "exceptionhandler.h"
597 #include "supernova.h"
598 #include "hudshield.h"
599 // #include "names.h"
601 #include "missionloopbrief.h"
605 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
611 // 1.00.04 5/26/98 MWA -- going final (12 pm)
612 // 1.00.03 5/26/98 MWA -- going final (3 am)
613 // 1.00.02 5/25/98 MWA -- going final
614 // 1.00.01 5/25/98 MWA -- going final
615 // 0.90 5/21/98 MWA -- getting ready for final.
616 // 0.10 4/9/98. Set by MK.
618 // Demo version: (obsolete since DEMO codebase split from tree)
619 // 0.03 4/10/98 AL. Interplay rev
620 // 0.02 4/8/98 MK. Increased when this system was modified.
621 // 0.01 4/7/98? AL. First release to Interplay QA.
624 // 1.00 5/28/98 AL. First release to Interplay QA.
626 void game_level_init(int seed = -1);
627 void game_post_level_init();
628 void game_do_frame();
629 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
630 void game_reset_time();
631 void game_show_framerate(); // draws framerate in lower right corner
633 int Game_no_clear = 0;
635 int Pofview_running = 0;
636 int Nebedit_running = 0;
638 typedef struct big_expl_flash {
639 float max_flash_intensity; // max intensity
640 float cur_flash_intensity; // cur intensity
641 int flash_start; // start time
644 #define FRAME_FILTER 16
646 #define DEFAULT_SKILL_LEVEL 1
647 int Game_skill_level = DEFAULT_SKILL_LEVEL;
649 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
650 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
652 #define EXE_FNAME ("fs2.exe")
653 #define LAUNCHER_FNAME ("freespace2.exe")
655 // JAS: Code for warphole camera.
656 // Needs to be cleaned up.
657 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
658 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
659 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
660 matrix Camera_orient = IDENTITY_MATRIX;
661 float Camera_damping = 1.0f;
662 float Camera_time = 0.0f;
663 float Warpout_time = 0.0f;
664 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
665 int Warpout_sound = -1;
667 int Use_joy_mouse = 0;
668 int Use_palette_flash = 1;
670 int Use_fullscreen_at_startup = 0;
672 int Show_area_effect = 0;
673 object *Last_view_target = NULL;
675 int dogfight_blown = 0;
678 float frametimes[FRAME_FILTER];
679 float frametotal = 0.0f;
683 int Show_framerate = 0;
685 int Show_framerate = 1;
688 int Framerate_cap = 120;
691 int Show_target_debug_info = 0;
692 int Show_target_weapons = 0;
694 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
696 int Debug_octant = -1;
698 fix Game_time_compression = F1_0;
700 // if the ships.tbl the player has is valid
701 int Game_ships_tbl_valid = 0;
703 // if the weapons.tbl the player has is valid
704 int Game_weapons_tbl_valid = 0;
708 extern int Player_attacking_enabled;
712 int Pre_player_entry;
714 int Fred_running = 0;
715 char Game_current_mission_filename[MAX_FILENAME_LEN];
716 int game_single_step = 0;
717 int last_single_step=0;
719 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
720 extern int MSG_WINDOW_Y_START;
721 extern int MSG_WINDOW_HEIGHT;
723 int game_zbuffer = 1;
724 //static int Game_music_paused;
725 static int Game_paused;
729 #define EXPIRE_BAD_CHECKSUM 1
730 #define EXPIRE_BAD_TIME 2
732 extern void ssm_init();
733 extern void ssm_level_init();
734 extern void ssm_process();
736 // static variable to contain the time this version was built
737 // commented out for now until
738 // I figure out how to get the username into the file
739 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
741 // defines and variables used for dumping frame for making trailers.
743 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
744 int Debug_dump_trigger = 0;
745 int Debug_dump_frame_count;
746 int Debug_dump_frame_num = 0;
747 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
750 // amount of time to wait after the player has died before we display the death died popup
751 #define PLAYER_DIED_POPUP_WAIT 2500
752 int Player_died_popup_wait = -1;
753 int Player_multi_died_check = -1;
755 // builtin mission list stuff
757 int Game_builtin_mission_count = 6;
758 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
759 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
760 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
761 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
762 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
763 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
764 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
766 #elif defined(PD_BUILD)
767 int Game_builtin_mission_count = 4;
768 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
769 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
770 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
771 { "sm1-01", (FSB_FROM_VOLITION), "" },
772 { "sm1-05", (FSB_FROM_VOLITION), "" },
774 #elif defined(MULTIPLAYER_BETA)
775 int Game_builtin_mission_count = 17;
776 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
778 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
779 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
780 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
781 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
782 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
783 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
784 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
785 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
786 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
787 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
788 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
789 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
790 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
791 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
792 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
793 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
794 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
796 #elif defined(OEM_BUILD)
797 int Game_builtin_mission_count = 17;
798 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
799 // oem version - act 1 only
800 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
803 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
804 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
805 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
806 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
807 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
808 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
809 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
810 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
811 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
812 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
813 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
814 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
815 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
816 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
817 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
818 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
821 int Game_builtin_mission_count = 92;
822 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
823 // single player campaign
824 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
827 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
828 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
829 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
830 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
831 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
832 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
833 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
835 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
836 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
838 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
839 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
841 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
842 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
843 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
844 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
845 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
848 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
850 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
851 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
853 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
854 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
861 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
864 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
865 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
866 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
867 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
868 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
869 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
870 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
871 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
873 // multiplayer missions
876 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
922 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
930 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
931 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
932 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
933 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
938 // Internal function prototypes
939 void game_maybe_draw_mouse(float frametime);
940 void init_animating_pointer();
941 void load_animating_pointer(char *filename, int dx, int dy);
942 void unload_animating_pointer();
943 void game_do_training_checks();
944 void game_shutdown(void);
945 void game_show_event_debug(float frametime);
946 void game_event_debug_init();
948 void demo_upsell_show_screens();
949 void game_start_subspace_ambient_sound();
950 void game_stop_subspace_ambient_sound();
951 void verify_ships_tbl();
952 void verify_weapons_tbl();
953 void display_title_screen();
955 // loading background filenames
956 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
957 "LoadingBG", // GR_640
958 "2_LoadingBG" // GR_1024
962 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
963 "Loading.ani", // GR_640
964 "2_Loading.ani" // GR_1024
967 #if defined(FS2_DEMO)
968 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
972 #elif defined(OEM_BUILD)
973 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
980 char Game_CDROM_dir[MAX_PATH_LEN];
983 // How much RAM is on this machine. Set in WinMain
984 uint Freespace_total_ram = 0;
987 float Game_flash_red = 0.0f;
988 float Game_flash_green = 0.0f;
989 float Game_flash_blue = 0.0f;
990 float Sun_spot = 0.0f;
991 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
993 // game shudder stuff (in ms)
994 int Game_shudder_time = -1;
995 int Game_shudder_total = 0;
996 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
999 sound_env Game_sound_env;
1000 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1001 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1003 int Game_sound_env_update_timestamp;
1005 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1008 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1010 fs_builtin_mission *game_find_builtin_mission(char *filename)
1014 // look through all existing builtin missions
1015 for(idx=0; idx<Game_builtin_mission_count; idx++){
1016 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1017 return &Game_builtin_mission_list[idx];
1025 int game_get_default_skill_level()
1027 return DEFAULT_SKILL_LEVEL;
1031 void game_flash_reset()
1033 Game_flash_red = 0.0f;
1034 Game_flash_green = 0.0f;
1035 Game_flash_blue = 0.0f;
1037 Big_expl_flash.max_flash_intensity = 0.0f;
1038 Big_expl_flash.cur_flash_intensity = 0.0f;
1039 Big_expl_flash.flash_start = 0;
1042 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1043 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1045 void game_framerate_check_init()
1047 // zero critical time
1048 Gf_critical_time = 0.0f;
1051 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1052 // if this is a glide card
1053 if(gr_screen.mode == GR_GLIDE){
1055 extern GrHwConfiguration hwconfig;
1058 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1059 Gf_critical = 15.0f;
1063 Gf_critical = 10.0f;
1068 Gf_critical = 15.0f;
1071 // d3d. only care about good cards here I guess (TNT)
1073 Gf_critical = 15.0f;
1076 // if this is a glide card
1077 if(gr_screen.mode == GR_GLIDE){
1079 extern GrHwConfiguration hwconfig;
1082 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1083 Gf_critical = 25.0f;
1087 Gf_critical = 20.0f;
1092 Gf_critical = 25.0f;
1095 // d3d. only care about good cards here I guess (TNT)
1097 Gf_critical = 25.0f;
1102 extern float Framerate;
1103 void game_framerate_check()
1107 // if the current framerate is above the critical level, add frametime
1108 if(Framerate >= Gf_critical){
1109 Gf_critical_time += flFrametime;
1112 if(!Show_framerate){
1116 // display if we're above the critical framerate
1117 if(Framerate < Gf_critical){
1118 gr_set_color_fast(&Color_bright_red);
1119 gr_string(200, y_start, "Framerate warning");
1124 // display our current pct of good frametime
1125 if(f2fl(Missiontime) >= 0.0f){
1126 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1129 gr_set_color_fast(&Color_bright_green);
1131 gr_set_color_fast(&Color_bright_red);
1134 gr_printf(200, y_start, "%d%%", (int)pct);
1141 // Adds a flash effect. These can be positive or negative.
1142 // The range will get capped at around -1 to 1, so stick
1143 // with a range like that.
1144 void game_flash( float r, float g, float b )
1146 Game_flash_red += r;
1147 Game_flash_green += g;
1148 Game_flash_blue += b;
1150 if ( Game_flash_red < -1.0f ) {
1151 Game_flash_red = -1.0f;
1152 } else if ( Game_flash_red > 1.0f ) {
1153 Game_flash_red = 1.0f;
1156 if ( Game_flash_green < -1.0f ) {
1157 Game_flash_green = -1.0f;
1158 } else if ( Game_flash_green > 1.0f ) {
1159 Game_flash_green = 1.0f;
1162 if ( Game_flash_blue < -1.0f ) {
1163 Game_flash_blue = -1.0f;
1164 } else if ( Game_flash_blue > 1.0f ) {
1165 Game_flash_blue = 1.0f;
1170 // Adds a flash for Big Ship explosions
1171 // cap range from 0 to 1
1172 void big_explosion_flash(float flash)
1174 Big_expl_flash.flash_start = timestamp(1);
1178 } else if (flash < 0.0f) {
1182 Big_expl_flash.max_flash_intensity = flash;
1183 Big_expl_flash.cur_flash_intensity = 0.0f;
1186 // Amount to diminish palette towards normal, per second.
1187 #define DIMINISH_RATE 0.75f
1188 #define SUN_DIMINISH_RATE 6.00f
1192 float sn_glare_scale = 1.7f;
1195 dc_get_arg(ARG_FLOAT);
1196 sn_glare_scale = Dc_arg_float;
1199 float Supernova_last_glare = 0.0f;
1200 void game_sunspot_process(float frametime)
1204 float Sun_spot_goal = 0.0f;
1207 sn_stage = supernova_active();
1209 // sunspot differently based on supernova stage
1211 // approaching. player still in control
1214 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1217 light_get_global_dir(&light_dir, 0);
1219 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1222 // scale it some more
1223 dot = dot * (0.5f + (pct * 0.5f));
1226 Sun_spot_goal += (dot * sn_glare_scale);
1229 // draw the sun glow
1230 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1231 // draw the glow for this sun
1232 stars_draw_sun_glow(0);
1235 Supernova_last_glare = Sun_spot_goal;
1238 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1241 Sun_spot_goal = 0.9f;
1242 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1244 if(Sun_spot_goal > 1.0f){
1245 Sun_spot_goal = 1.0f;
1248 Sun_spot_goal *= sn_glare_scale;
1249 Supernova_last_glare = Sun_spot_goal;
1252 // fade to white. display dead popup
1255 Supernova_last_glare += (2.0f * flFrametime);
1256 if(Supernova_last_glare > 2.0f){
1257 Supernova_last_glare = 2.0f;
1260 Sun_spot_goal = Supernova_last_glare;
1267 // check sunspots for all suns
1268 n_lights = light_get_global_count();
1271 for(idx=0; idx<n_lights; idx++){
1272 //(vector *eye_pos, matrix *eye_orient)
1273 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1276 light_get_global_dir(&light_dir, idx);
1278 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1280 Sun_spot_goal += (float)pow(dot,85.0f);
1282 // draw the glow for this sun
1283 stars_draw_sun_glow(idx);
1285 Sun_spot_goal = 0.0f;
1291 Sun_spot_goal = 0.0f;
1295 float dec_amount = frametime*SUN_DIMINISH_RATE;
1297 if ( Sun_spot < Sun_spot_goal ) {
1298 Sun_spot += dec_amount;
1299 if ( Sun_spot > Sun_spot_goal ) {
1300 Sun_spot = Sun_spot_goal;
1302 } else if ( Sun_spot > Sun_spot_goal ) {
1303 Sun_spot -= dec_amount;
1304 if ( Sun_spot < Sun_spot_goal ) {
1305 Sun_spot = Sun_spot_goal;
1311 // Call once a frame to diminish the
1312 // flash effect to 0.
1313 void game_flash_diminish(float frametime)
1315 float dec_amount = frametime*DIMINISH_RATE;
1317 if ( Game_flash_red > 0.0f ) {
1318 Game_flash_red -= dec_amount;
1319 if ( Game_flash_red < 0.0f )
1320 Game_flash_red = 0.0f;
1322 Game_flash_red += dec_amount;
1323 if ( Game_flash_red > 0.0f )
1324 Game_flash_red = 0.0f;
1327 if ( Game_flash_green > 0.0f ) {
1328 Game_flash_green -= dec_amount;
1329 if ( Game_flash_green < 0.0f )
1330 Game_flash_green = 0.0f;
1332 Game_flash_green += dec_amount;
1333 if ( Game_flash_green > 0.0f )
1334 Game_flash_green = 0.0f;
1337 if ( Game_flash_blue > 0.0f ) {
1338 Game_flash_blue -= dec_amount;
1339 if ( Game_flash_blue < 0.0f )
1340 Game_flash_blue = 0.0f;
1342 Game_flash_blue += dec_amount;
1343 if ( Game_flash_blue > 0.0f )
1344 Game_flash_blue = 0.0f;
1347 // update big_explosion_cur_flash
1348 #define TIME_UP 1500
1349 #define TIME_DOWN 2500
1350 int duration = TIME_UP + TIME_DOWN;
1351 int time = timestamp_until(Big_expl_flash.flash_start);
1352 if (time > -duration) {
1354 if (time < TIME_UP) {
1355 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1358 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1362 if ( Use_palette_flash ) {
1364 // static int or=0, og=0, ob=0;
1366 // Change the 200 to change the color range of colors.
1367 r = fl2i( Game_flash_red*128.0f );
1368 g = fl2i( Game_flash_green*128.0f );
1369 b = fl2i( Game_flash_blue*128.0f );
1371 if ( Sun_spot > 0.0f ) {
1372 r += fl2i(Sun_spot*128.0f);
1373 g += fl2i(Sun_spot*128.0f);
1374 b += fl2i(Sun_spot*128.0f);
1377 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1378 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1379 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1380 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1383 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1384 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1385 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1387 if ( (r!=0) || (g!=0) || (b!=0) ) {
1388 gr_flash( r, g, b );
1390 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1401 void game_level_close()
1403 // De-Initialize the game subsystems
1404 message_mission_shutdown();
1405 event_music_level_close();
1406 game_stop_looped_sounds();
1408 obj_snd_level_close(); // uninit object-linked persistant sounds
1409 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1410 anim_level_close(); // stop and clean up any anim instances
1411 shockwave_level_close();
1412 fireball_level_close();
1414 mission_event_shutdown();
1415 asteroid_level_close();
1416 model_cache_reset(); // Reset/free all the model caching stuff
1417 flak_level_close(); // unload flak stuff
1418 neb2_level_close(); // shutdown gaseous nebula stuff
1421 mflash_level_close();
1423 audiostream_unpause_all();
1428 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1429 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1430 void game_level_init(int seed)
1432 // seed the random number generator
1434 // if no seed was passed, seed the generator either from the time value, or from the
1435 // netgame security flags -- ensures that all players in multiplayer game will have the
1436 // same randon number sequence (with static rand functions)
1437 if ( Game_mode & GM_NORMAL ) {
1438 Game_level_seed = time(NULL);
1440 Game_level_seed = Netgame.security;
1443 // mwa 9/17/98 -- maybe this assert isn't needed????
1444 Assert( !(Game_mode & GM_MULTIPLAYER) );
1445 Game_level_seed = seed;
1447 srand( Game_level_seed );
1449 // semirand function needs to get re-initted every time in multiplayer
1450 if ( Game_mode & GM_MULTIPLAYER ){
1456 Key_normal_game = (Game_mode & GM_NORMAL);
1459 Game_shudder_time = -1;
1461 // Initialize the game subsystems
1462 // timestamp_reset(); // Must be inited before everything else
1464 game_reset_time(); // resets time, and resets saved time too
1466 obj_init(); // Must be inited before the other systems
1467 model_free_all(); // Free all existing models
1468 mission_brief_common_init(); // Free all existing briefing/debriefing text
1469 weapon_level_init();
1470 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1472 player_level_init();
1473 shipfx_flash_init(); // Init the ship gun flash system.
1474 game_flash_reset(); // Reset the flash effect
1475 particle_init(); // Reset the particle system
1479 shield_hit_init(); // Initialize system for showing shield hits
1480 radar_mission_init();
1481 mission_init_goals();
1484 obj_snd_level_init(); // init object-linked persistant sounds
1486 shockwave_level_init();
1487 afterburner_level_init();
1488 scoring_level_init( &Player->stats );
1490 asteroid_level_init();
1491 control_config_clear_used_status();
1492 collide_ship_ship_sounds_init();
1494 Pre_player_entry = 1; // Means the player has not yet entered.
1495 Entry_delay_time = 0; // Could get overwritten in mission read.
1496 fireball_preload(); // page in warphole bitmaps
1498 flak_level_init(); // initialize flak - bitmaps, etc
1499 ct_level_init(); // initialize ships contrails, etc
1500 awacs_level_init(); // initialize AWACS
1501 beam_level_init(); // initialize beam weapons
1502 mflash_level_init();
1504 supernova_level_init();
1506 // multiplayer dogfight hack
1509 shipfx_engine_wash_level_init();
1513 Last_view_target = NULL;
1518 // campaign wasn't ended
1519 Campaign_ended_in_mission = 0;
1522 // called when a mission is over -- does server specific stuff.
1523 void freespace_stop_mission()
1526 Game_mode &= ~GM_IN_MISSION;
1529 // called at frame interval to process networking stuff
1530 void game_do_networking()
1532 Assert( Net_player != NULL );
1533 if (!(Game_mode & GM_MULTIPLAYER)){
1537 // see if this player should be reading/writing data. Bit is set when at join
1538 // screen onward until quits back to main menu.
1539 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1543 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1546 multi_pause_do_frame();
1551 // Loads the best palette for this level, based
1552 // on nebula color and hud color. You could just call palette_load_table with
1553 // the appropriate filename, but who wants to do that.
1554 void game_load_palette()
1556 char palette_filename[1024];
1558 // We only use 3 hud colors right now
1559 // Assert( HUD_config.color >= 0 );
1560 // Assert( HUD_config.color <= 2 );
1562 Assert( Mission_palette >= 0 );
1563 Assert( Mission_palette <= 98 );
1565 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1566 strcpy( palette_filename, NOX("gamepalette-subspace") );
1568 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1571 mprintf(( "Loading palette %s\n", palette_filename ));
1573 // palette_load_table(palette_filename);
1576 void game_post_level_init()
1578 // Stuff which gets called after mission is loaded. Because player isn't created until
1579 // after mission loads, some things must get initted after the level loads
1581 model_level_post_init();
1584 hud_setup_escort_list();
1585 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1591 game_event_debug_init();
1594 training_mission_init();
1595 asteroid_create_all();
1597 game_framerate_check_init();
1601 // An estimate as to how high the count passed to game_loading_callback will go.
1602 // This is just a guess, it seems to always be about the same. The count is
1603 // proportional to the code being executed, not the time, so this works good
1604 // for a bar, assuming the code does about the same thing each time you
1605 // load a level. You can find this value by looking at the return value
1606 // of game_busy_callback(NULL), which I conveniently print out to the
1607 // debug output window with the '=== ENDING LOAD ==' stuff.
1608 //#define COUNT_ESTIMATE 3706
1609 #define COUNT_ESTIMATE 1111
1611 int Game_loading_callback_inited = 0;
1613 int Game_loading_background = -1;
1614 anim * Game_loading_ani = NULL;
1615 anim_instance *Game_loading_ani_instance;
1616 int Game_loading_frame=-1;
1618 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1627 // This gets called 10x per second and count is the number of times
1628 // game_busy() has been called since the current callback function
1630 void game_loading_callback(int count)
1632 game_do_networking();
1634 Assert( Game_loading_callback_inited==1 );
1635 Assert( Game_loading_ani != NULL );
1637 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1638 if ( framenum > Game_loading_ani->total_frames-1 ) {
1639 framenum = Game_loading_ani->total_frames-1;
1640 } else if ( framenum < 0 ) {
1645 while ( Game_loading_frame < framenum ) {
1646 Game_loading_frame++;
1647 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1651 if ( cbitmap > -1 ) {
1652 if ( Game_loading_background > -1 ) {
1653 gr_set_bitmap( Game_loading_background );
1657 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1658 gr_set_bitmap( cbitmap );
1659 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1661 bm_release(cbitmap);
1667 void game_loading_callback_init()
1669 Assert( Game_loading_callback_inited==0 );
1671 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1672 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1675 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1676 Assert( Game_loading_ani != NULL );
1677 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1678 Assert( Game_loading_ani_instance != NULL );
1679 Game_loading_frame = -1;
1681 Game_loading_callback_inited = 1;
1683 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1688 void game_loading_callback_close()
1690 Assert( Game_loading_callback_inited==1 );
1692 // Make sure bar shows all the way over.
1693 game_loading_callback(COUNT_ESTIMATE);
1695 int real_count = game_busy_callback( NULL );
1698 Game_loading_callback_inited = 0;
1701 mprintf(( "=================== ENDING LOAD ================\n" ));
1702 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1703 mprintf(( "================================================\n" ));
1705 // to remove warnings in release build
1709 free_anim_instance(Game_loading_ani_instance);
1710 Game_loading_ani_instance = NULL;
1711 anim_free(Game_loading_ani);
1712 Game_loading_ani = NULL;
1714 bm_release( Game_loading_background );
1715 common_free_interface_palette(); // restore game palette
1716 Game_loading_background = -1;
1718 gr_set_font( FONT1 );
1721 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1723 void game_maybe_update_sound_environment()
1725 // do nothing for now
1728 // Assign the sound environment for the game, based on the current mission
1730 void game_assign_sound_environment()
1733 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1734 Game_sound_env.id = SND_ENV_DRUGGED;
1735 Game_sound_env.volume = 0.800f;
1736 Game_sound_env.damping = 1.188f;
1737 Game_sound_env.decay = 6.392f;
1739 } else if (Num_asteroids > 30) {
1740 Game_sound_env.id = SND_ENV_AUDITORIUM;
1741 Game_sound_env.volume = 0.603f;
1742 Game_sound_env.damping = 0.5f;
1743 Game_sound_env.decay = 4.279f;
1746 Game_sound_env = Game_default_sound_env;
1750 Game_sound_env = Game_default_sound_env;
1751 Game_sound_env_update_timestamp = timestamp(1);
1754 // function which gets called before actually entering the mission. It is broken down into a funciton
1755 // since it will get called in one place from a single player game and from another place for
1756 // a multiplayer game
1757 void freespace_mission_load_stuff()
1759 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1760 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1761 if(!(Game_mode & GM_STANDALONE_SERVER)){
1763 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1765 game_loading_callback_init();
1767 event_music_level_init(); // preloads the first 2 seconds for each event music track
1770 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1773 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1776 ship_assign_sound_all(); // assign engine sounds to ships
1777 game_assign_sound_environment(); // assign the sound environment for this mission
1780 // call function in missionparse.cpp to fixup player/ai stuff.
1781 mission_parse_fixup_players();
1784 // Load in all the bitmaps for this level
1789 game_loading_callback_close();
1791 // the only thing we need to call on the standalone for now.
1793 // call function in missionparse.cpp to fixup player/ai stuff.
1794 mission_parse_fixup_players();
1796 // Load in all the bitmaps for this level
1802 uint load_mission_load;
1803 uint load_post_level_init;
1804 uint load_mission_stuff;
1806 // tells the server to load the mission and initialize structures
1807 int game_start_mission()
1809 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1811 load_gl_init = time(NULL);
1813 load_gl_init = time(NULL) - load_gl_init;
1815 if (Game_mode & GM_MULTIPLAYER) {
1816 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1818 // clear multiplayer stats
1819 init_multiplayer_stats();
1822 load_mission_load = time(NULL);
1823 if (mission_load()) {
1824 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1825 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1826 gameseq_post_event(GS_EVENT_MAIN_MENU);
1828 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1833 load_mission_load = time(NULL) - load_mission_load;
1835 // If this is a red alert mission in campaign mode, bash wingman status
1836 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1837 red_alert_bash_wingman_status();
1840 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1841 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1842 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1843 // game_load_palette();
1846 load_post_level_init = time(NULL);
1847 game_post_level_init();
1848 load_post_level_init = time(NULL) - load_post_level_init;
1852 void Do_model_timings_test();
1853 Do_model_timings_test();
1857 load_mission_stuff = time(NULL);
1858 freespace_mission_load_stuff();
1859 load_mission_stuff = time(NULL) - load_mission_stuff;
1864 int Interface_framerate = 0;
1867 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1868 DCF_BOOL( show_framerate, Show_framerate )
1869 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1870 DCF_BOOL( show_target_weapons, Show_target_weapons )
1871 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1872 DCF_BOOL( sound, Sound_enabled )
1873 DCF_BOOL( zbuffer, game_zbuffer )
1874 DCF_BOOL( shield_system, New_shield_system )
1875 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1876 DCF_BOOL( player_attacking, Player_attacking_enabled )
1877 DCF_BOOL( show_waypoints, Show_waypoints )
1878 DCF_BOOL( show_area_effect, Show_area_effect )
1879 DCF_BOOL( show_net_stats, Show_net_stats )
1880 DCF_BOOL( log, Log_debug_output_to_file )
1881 DCF_BOOL( training_msg_method, Training_msg_method )
1882 DCF_BOOL( show_player_pos, Show_player_pos )
1883 DCF_BOOL(i_framerate, Interface_framerate )
1885 DCF(show_mem,"Toggles showing mem usage")
1888 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1889 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1890 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1891 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1897 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1899 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1900 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1904 DCF(show_cpu,"Toggles showing cpu usage")
1907 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1908 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1909 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1910 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1916 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1918 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1919 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1926 // AL 4-8-98: always allow players to display their framerate
1929 DCF_BOOL( show_framerate, Show_framerate )
1936 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1939 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1940 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1941 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1942 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1944 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" );
1945 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1947 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1950 DCF(palette_flash,"Toggles palette flash effect on/off")
1953 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1954 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1955 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1956 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1958 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1959 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1962 int Use_low_mem = 0;
1964 DCF(low_mem,"Uses low memory settings regardless of RAM")
1967 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1968 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1969 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1970 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1972 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1973 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1975 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1981 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1984 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1985 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1986 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1987 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1989 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1990 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1991 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1995 int Framerate_delay = 0;
1997 float Freespace_gamma = 1.0f;
1999 DCF(gamma,"Sets Gamma factor")
2002 dc_get_arg(ARG_FLOAT|ARG_NONE);
2003 if ( Dc_arg_type & ARG_FLOAT ) {
2004 Freespace_gamma = Dc_arg_float;
2006 dc_printf( "Gamma reset to 1.0f\n" );
2007 Freespace_gamma = 1.0f;
2009 if ( Freespace_gamma < 0.1f ) {
2010 Freespace_gamma = 0.1f;
2011 } else if ( Freespace_gamma > 5.0f ) {
2012 Freespace_gamma = 5.0f;
2014 gr_set_gamma(Freespace_gamma);
2016 char tmp_gamma_string[32];
2017 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2018 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2022 dc_printf( "Usage: gamma <float>\n" );
2023 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2024 Dc_status = 0; // don't print status if help is printed. Too messy.
2028 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2037 Game_current_mission_filename[0] = 0;
2039 // seed the random number generator
2040 Game_init_seed = time(NULL);
2041 srand( Game_init_seed );
2043 Framerate_delay = 0;
2049 extern void bm_init();
2055 // Initialize the timer before the os
2063 GetCurrentDirectory(1024, whee);
2066 getcwd (whee, 1024);
2069 strcat(whee, EXE_FNAME);
2071 //Initialize the libraries
2072 s1 = timer_get_milliseconds();
2073 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2076 e1 = timer_get_milliseconds();
2078 // time a bunch of cfopens
2080 s2 = timer_get_milliseconds();
2082 for(int idx=0; idx<10000; idx++){
2083 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2088 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2090 e2 = timer_get_milliseconds();
2093 if (Is_standalone) {
2094 std_init_standalone();
2096 os_init( Osreg_class_name, Osreg_app_name );
2097 os_set_title(Osreg_title);
2100 // initialize localization module. Make sure this is down AFTER initialzing OS.
2101 // int t1 = timer_get_milliseconds();
2104 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2106 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2109 // verify that he has a valid weapons.tbl
2110 verify_weapons_tbl();
2112 // Output version numbers to registry for auto patching purposes
2113 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2114 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2115 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2117 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2118 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2119 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2122 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2126 Asteroids_enabled = 1;
2129 /////////////////////////////
2131 /////////////////////////////
2136 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2137 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2139 if (!stricmp(ptr, NOX("no sound"))) {
2140 Cmdline_freespace_no_sound = 1;
2142 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2144 } else if (!stricmp(ptr, NOX("EAX"))) {
2149 if (!Is_standalone) {
2150 snd_init(use_a3d, use_eax);
2152 /////////////////////////////
2154 /////////////////////////////
2156 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2159 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);
2161 // fire up the UpdateLauncher executable
2163 PROCESS_INFORMATION pi;
2165 memset( &si, 0, sizeof(STARTUPINFO) );
2168 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2169 NULL, // pointer to command line string
2170 NULL, // pointer to process security attributes
2171 NULL, // pointer to thread security attributes
2172 FALSE, // handle inheritance flag
2173 CREATE_DEFAULT_ERROR_MODE, // creation flags
2174 NULL, // pointer to new environment block
2175 NULL, // pointer to current directory name
2176 &si, // pointer to STARTUPINFO
2177 &pi // pointer to PROCESS_INFORMATION
2180 // If the Launcher could not be started up, let the user know
2182 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2191 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2193 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);
2201 // check for hi res pack file
2202 int has_sparky_hi = 0;
2204 // check if sparky_hi exists -- access mode 0 means does file exist
2207 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2210 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2213 // see if we've got 32 bit in the string
2214 if(strstr(ptr, "32 bit")){
2221 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2223 // always 640 for E3
2224 gr_init(GR_640, GR_GLIDE);
2226 // regular or hi-res ?
2228 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2230 if(strstr(ptr, NOX("(1024x768)"))){
2232 gr_init(GR_1024, GR_GLIDE);
2234 gr_init(GR_640, GR_GLIDE);
2237 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2239 // always 640 for E3
2241 gr_init(GR_640, GR_DIRECT3D, depth);
2243 // regular or hi-res ?
2245 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2247 if(strstr(ptr, NOX("(1024x768)"))){
2251 gr_init(GR_1024, GR_DIRECT3D, depth);
2255 gr_init(GR_640, GR_DIRECT3D, depth);
2261 if ( Use_fullscreen_at_startup && !Is_standalone) {
2262 gr_init(GR_640, GR_DIRECTDRAW);
2264 gr_init(GR_640, GR_SOFTWARE);
2267 if ( !Is_standalone ) {
2268 gr_init(GR_640, GR_DIRECTDRAW);
2270 gr_init(GR_640, GR_SOFTWARE);
2275 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2276 if(strstr(ptr, NOX("(1024x768)"))){
2277 gr_init(GR_1024, GR_OPENGL);
2279 gr_init(GR_640, GR_OPENGL);
2283 gr_init(GR_640, GR_SOFTWARE);
2288 extern int Gr_inited;
2289 if(trying_d3d && !Gr_inited){
2290 extern char Device_init_error[512];
2292 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2301 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2302 Freespace_gamma = (float)atof(ptr);
2303 if ( Freespace_gamma == 0.0f ) {
2304 Freespace_gamma = 1.80f;
2305 } else if ( Freespace_gamma < 0.1f ) {
2306 Freespace_gamma = 0.1f;
2307 } else if ( Freespace_gamma > 5.0f ) {
2308 Freespace_gamma = 5.0f;
2310 char tmp_gamma_string[32];
2311 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2312 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2314 gr_set_gamma(Freespace_gamma);
2316 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2319 display_title_screen();
2323 // attempt to load up master tracker registry info (login and password)
2324 Multi_tracker_id = -1;
2326 // pxo login and password
2327 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2329 nprintf(("Network","Error reading in PXO login data\n"));
2330 strcpy(Multi_tracker_login,"");
2332 strcpy(Multi_tracker_login,ptr);
2334 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2336 nprintf(("Network","Error reading PXO password\n"));
2337 strcpy(Multi_tracker_passwd,"");
2339 strcpy(Multi_tracker_passwd,ptr);
2342 // pxo squad name and password
2343 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2345 nprintf(("Network","Error reading in PXO squad name\n"));
2346 strcpy(Multi_tracker_squad_name, "");
2348 strcpy(Multi_tracker_squad_name, ptr);
2351 // If less than 48MB of RAM, use low memory model.
2352 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2353 mprintf(( "Using normal memory settings...\n" ));
2354 bm_set_low_mem(1); // Use every other frame of bitmaps
2356 mprintf(( "Using high memory settings...\n" ));
2357 bm_set_low_mem(0); // Use all frames of bitmaps
2360 // load non-darkening pixel defs
2361 palman_load_pixels();
2363 // hud shield icon stuff
2364 hud_shield_game_init();
2366 control_config_common_init(); // sets up localization stuff in the control config
2372 gamesnd_parse_soundstbl();
2377 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2382 player_controls_init();
2385 //if(!Is_standalone){
2393 ship_init(); // read in ships.tbl
2395 mission_campaign_init(); // load in the default campaign
2397 // navmap_init(); // init the navigation map system
2398 context_help_init();
2399 techroom_intel_init(); // parse species.tbl, load intel info
2401 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2402 init_animating_pointer();
2404 mission_brief_common_init(); // Mark all the briefing structures as empty.
2405 gr_font_init(); // loads up all fonts
2407 neb2_init(); // fullneb stuff
2411 player_tips_init(); // helpful tips
2414 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2415 pilot_load_pic_list();
2416 pilot_load_squad_pic_list();
2418 load_animating_pointer(NOX("cursor"), 0, 0);
2420 // initialize alpha colors
2421 alpha_colors_init();
2424 // Game_music_paused = 0;
2431 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2432 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2434 mprintf(("cfile_init() took %d\n", e1 - s1));
2435 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2438 char transfer_text[128];
2440 float Start_time = 0.0f;
2442 float Framerate = 0.0f;
2444 float Timing_total = 0.0f;
2445 float Timing_render2 = 0.0f;
2446 float Timing_render3 = 0.0f;
2447 float Timing_flip = 0.0f;
2448 float Timing_clear = 0.0f;
2450 MONITOR(NumPolysDrawn);
2456 void game_get_framerate()
2458 char text[128] = "";
2460 if ( frame_int == -1 ) {
2462 for (i=0; i<FRAME_FILTER; i++ ) {
2463 frametimes[i] = 0.0f;
2468 frametotal -= frametimes[frame_int];
2469 frametotal += flFrametime;
2470 frametimes[frame_int] = flFrametime;
2471 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2473 if ( frametotal != 0.0 ) {
2474 if ( Framecount >= FRAME_FILTER )
2475 Framerate = FRAME_FILTER / frametotal;
2477 Framerate = Framecount / frametotal;
2478 sprintf( text, NOX("FPS: %.1f"), Framerate );
2480 sprintf( text, NOX("FPS: ?") );
2484 if (Show_framerate) {
2485 gr_set_color_fast(&HUD_color_debug);
2486 gr_string( 570, 2, text );
2490 void game_show_framerate()
2494 cur_time = f2fl(timer_get_approx_seconds());
2495 if (cur_time - Start_time > 30.0f) {
2496 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2497 Start_time += 1000.0f;
2500 //mprintf(( "%s\n", text ));
2503 if ( Debug_dump_frames )
2507 // possibly show control checking info
2508 control_check_indicate();
2510 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2511 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2512 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2513 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2516 if ( Show_cpu == 1 ) {
2521 dy = gr_get_font_height() + 1;
2523 gr_set_color_fast(&HUD_color_debug);
2527 extern int D3D_textures_in;
2528 extern int D3D_textures_in_frame;
2529 extern int Glide_textures_in;
2530 extern int Glide_textures_in_frame;
2531 extern int Glide_explosion_vram;
2532 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2534 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2536 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2542 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2544 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2546 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2548 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2550 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2555 extern int Num_pairs; // Number of object pairs that were checked.
2556 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2559 extern int Num_pairs_checked; // What percent of object pairs were checked.
2560 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2562 Num_pairs_checked = 0;
2566 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2569 if ( Timing_total > 0.01f ) {
2570 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2572 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2574 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2576 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2578 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2588 dy = gr_get_font_height() + 1;
2590 gr_set_color_fast(&HUD_color_debug);
2593 extern int TotalRam;
2594 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2599 extern int Model_ram;
2600 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2604 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2606 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2608 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2612 extern int D3D_textures_in;
2613 extern int Glide_textures_in;
2614 extern int Glide_textures_in_frame;
2615 extern int Glide_explosion_vram;
2616 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2618 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2620 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2629 if ( Show_player_pos ) {
2633 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));
2636 MONITOR_INC(NumPolys, modelstats_num_polys);
2637 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2638 MONITOR_INC(NumVerts, modelstats_num_verts );
2640 modelstats_num_polys = 0;
2641 modelstats_num_polys_drawn = 0;
2642 modelstats_num_verts = 0;
2643 modelstats_num_sortnorms = 0;
2647 void game_show_standalone_framerate()
2649 float frame_rate=30.0f;
2650 if ( frame_int == -1 ) {
2652 for (i=0; i<FRAME_FILTER; i++ ) {
2653 frametimes[i] = 0.0f;
2658 frametotal -= frametimes[frame_int];
2659 frametotal += flFrametime;
2660 frametimes[frame_int] = flFrametime;
2661 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2663 if ( frametotal != 0.0 ) {
2664 if ( Framecount >= FRAME_FILTER ){
2665 frame_rate = FRAME_FILTER / frametotal;
2667 frame_rate = Framecount / frametotal;
2670 std_set_standalone_fps(frame_rate);
2674 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2675 void game_show_time_left()
2679 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2680 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2681 // checking how much time is left
2683 if ( Mission_end_time == -1 ){
2687 diff = f2i(Mission_end_time - Missiontime);
2688 // be sure to bash to 0. diff could be negative on frame that we quit mission
2693 hud_set_default_color();
2694 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2697 //========================================================================================
2698 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2699 //========================================================================================
2703 DCF(ai_pause,"Pauses ai")
2706 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2707 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2708 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2709 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2712 obj_init_all_ships_physics();
2715 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2716 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2719 DCF(single_step,"Single steps the game")
2722 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2723 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2724 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2725 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2727 last_single_step = 0; // Make so single step waits a frame before stepping
2730 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2731 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2734 DCF_BOOL(physics_pause, physics_paused)
2735 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2736 DCF_BOOL(ai_firing, Ai_firing_enabled )
2738 // Create some simple aliases to these commands...
2739 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2740 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2741 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2742 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2743 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2746 //========================================================================================
2747 //========================================================================================
2750 void game_training_pause_do()
2754 key = game_check_key();
2756 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2763 void game_increase_skill_level()
2766 if (Game_skill_level >= NUM_SKILL_LEVELS){
2767 Game_skill_level = 0;
2771 int Player_died_time;
2773 int View_percent = 100;
2776 DCF(view, "Sets the percent of the 3d view to render.")
2779 dc_get_arg(ARG_INT);
2780 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2781 View_percent = Dc_arg_int;
2783 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2789 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2793 dc_printf("View is set to %d%%\n", View_percent );
2798 // Set the clip region for the 3d rendering window
2799 void game_set_view_clip()
2801 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2802 // Set the clip region for the letterbox "dead view"
2803 int yborder = gr_screen.max_h/4;
2805 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2806 // J.S. I've changed my ways!! See the new "no constants" code!!!
2807 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2809 // Set the clip region for normal view
2810 if ( View_percent >= 100 ) {
2813 int xborder, yborder;
2815 if ( View_percent < 5 ) {
2819 float fp = i2fl(View_percent)/100.0f;
2820 int fi = fl2i(fl_sqrt(fp)*100.0f);
2821 if ( fi > 100 ) fi=100;
2823 xborder = ( gr_screen.max_w*(100-fi) )/200;
2824 yborder = ( gr_screen.max_h*(100-fi) )/200;
2826 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2832 void show_debug_stuff()
2835 int laser_count = 0, missile_count = 0;
2837 for (i=0; i<MAX_OBJECTS; i++) {
2838 if (Objects[i].type == OBJ_WEAPON){
2839 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2841 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2847 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2850 extern int Tool_enabled;
2855 int tst_bitmap = -1;
2857 float tst_offset, tst_offset_total;
2860 void game_tst_frame_pre()
2868 g3_rotate_vertex(&v, &tst_pos);
2869 g3_project_vertex(&v);
2872 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2876 // big ship? always tst
2878 // within 3000 meters
2879 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2883 // within 300 meters
2884 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2891 void game_tst_frame()
2901 tst_time = time(NULL);
2903 // load the tst bitmap
2904 switch((int)frand_range(0.0f, 3.0)){
2906 tst_bitmap = bm_load("ig_jim");
2908 mprintf(("TST 0\n"));
2912 tst_bitmap = bm_load("ig_kan");
2914 mprintf(("TST 1\n"));
2918 tst_bitmap = bm_load("ig_jim");
2920 mprintf(("TST 2\n"));
2924 tst_bitmap = bm_load("ig_kan");
2926 mprintf(("TST 3\n"));
2935 // get the tst bitmap dimensions
2937 bm_get_info(tst_bitmap, &w, &h);
2940 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2942 snd_play(&Snds[SND_VASUDAN_BUP]);
2944 // tst x and direction
2948 tst_offset_total = (float)w;
2949 tst_offset = (float)w;
2951 tst_x = (float)gr_screen.max_w;
2952 tst_offset_total = (float)-w;
2953 tst_offset = (float)w;
2961 float diff = (tst_offset_total / 0.5f) * flFrametime;
2967 tst_offset -= fl_abs(diff);
2968 } else if(tst_mode == 2){
2971 tst_offset -= fl_abs(diff);
2975 gr_set_bitmap(tst_bitmap);
2976 gr_bitmap((int)tst_x, (int)tst_y);
2979 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2983 // if we passed the switch point
2984 if(tst_offset <= 0.0f){
2989 tst_stamp = timestamp(1000);
2990 tst_offset = fl_abs(tst_offset_total);
3001 void game_tst_mark(object *objp, ship *shipp)
3010 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3013 sip = &Ship_info[shipp->ship_info_index];
3020 tst_pos = objp->pos;
3021 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3027 extern void render_shields();
3029 void player_repair_frame(float frametime)
3031 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3033 for(idx=0;idx<MAX_PLAYERS;idx++){
3036 np = &Net_players[idx];
3038 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)){
3040 // don't rearm/repair if the player is dead or dying/departing
3041 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3042 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3047 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3048 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3054 #define NUM_FRAMES_TEST 300
3055 #define NUM_MIXED_SOUNDS 16
3056 void do_timing_test(float flFrametime)
3058 static int framecount = 0;
3059 static int test_running = 0;
3060 static float test_time = 0.0f;
3062 static int snds[NUM_MIXED_SOUNDS];
3065 if ( test_running ) {
3067 test_time += flFrametime;
3068 if ( framecount >= NUM_FRAMES_TEST ) {
3070 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3071 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3076 if ( Test_begin == 1 ) {
3082 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3085 // start looping digital sounds
3086 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3087 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3094 DCF(dcf_fov, "Change the field of view")
3097 dc_get_arg(ARG_FLOAT|ARG_NONE);
3098 if ( Dc_arg_type & ARG_NONE ) {
3099 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3100 dc_printf( "Zoom factor reset\n" );
3102 if ( Dc_arg_type & ARG_FLOAT ) {
3103 if (Dc_arg_float < 0.25f) {
3104 Viewer_zoom = 0.25f;
3105 dc_printf("Zoom factor pinned at 0.25.\n");
3106 } else if (Dc_arg_float > 1.25f) {
3107 Viewer_zoom = 1.25f;
3108 dc_printf("Zoom factor pinned at 1.25.\n");
3110 Viewer_zoom = Dc_arg_float;
3116 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3119 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3123 DCF(framerate_cap, "Sets the framerate cap")
3126 dc_get_arg(ARG_INT);
3127 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3128 Framerate_cap = Dc_arg_int;
3130 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3136 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3137 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3138 dc_printf("[n] must be from 1 to 120.\n");
3142 if ( Framerate_cap )
3143 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3145 dc_printf("There is no framerate cap currently active.\n");
3149 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3150 int Show_viewing_from_self = 0;
3152 void say_view_target()
3154 object *view_target;
3156 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3157 view_target = &Objects[Player_ai->target_objnum];
3159 view_target = Player_obj;
3161 if (Game_mode & GM_DEAD) {
3162 if (Player_ai->target_objnum != -1)
3163 view_target = &Objects[Player_ai->target_objnum];
3166 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3167 if (view_target != Player_obj){
3169 char *view_target_name = NULL;
3170 switch(Objects[Player_ai->target_objnum].type) {
3172 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3175 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3176 Viewer_mode &= ~VM_OTHER_SHIP;
3178 case OBJ_JUMP_NODE: {
3179 char jump_node_name[128];
3180 strcpy(jump_node_name, XSTR( "jump node", 184));
3181 view_target_name = jump_node_name;
3182 Viewer_mode &= ~VM_OTHER_SHIP;
3191 if ( view_target_name ) {
3192 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3193 Show_viewing_from_self = 1;
3196 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3197 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3198 Show_viewing_from_self = 1;
3200 if (Show_viewing_from_self)
3201 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3206 Last_view_target = view_target;
3210 float Game_hit_x = 0.0f;
3211 float Game_hit_y = 0.0f;
3213 // Reset at the beginning of each frame
3214 void game_whack_reset()
3220 // Apply a 2d whack to the player
3221 void game_whack_apply( float x, float y )
3223 // Do some force feedback
3224 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3230 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3233 // call to apply a "shudder"
3234 void game_shudder_apply(int time, float intensity)
3236 Game_shudder_time = timestamp(time);
3237 Game_shudder_total = time;
3238 Game_shudder_intensity = intensity;
3241 #define FF_SCALE 10000
3242 void apply_hud_shake(matrix *eye_orient)
3244 if (Viewer_obj == Player_obj) {
3245 physics_info *pi = &Player_obj->phys_info;
3253 // Make eye shake due to afterburner
3254 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3257 dtime = timestamp_until(pi->afterburner_decay);
3261 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3262 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3265 // Make eye shake due to engine wash
3267 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3270 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3271 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3273 // get the intensity
3274 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3278 vm_vec_rand_vec_quick(&rand_vec);
3281 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3285 // make hud shake due to shuddering
3286 if(Game_shudder_time != -1){
3287 // if the timestamp has elapsed
3288 if(timestamp_elapsed(Game_shudder_time)){
3289 Game_shudder_time = -1;
3291 // otherwise apply some shudder
3295 dtime = timestamp_until(Game_shudder_time);
3299 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));
3300 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));
3305 vm_angles_2_matrix(&tm, &tangles);
3306 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3307 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3308 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3309 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3314 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3316 // Player's velocity just before he blew up. Used to keep camera target moving.
3317 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3319 // Set eye_pos and eye_orient based on view mode.
3320 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3324 static int last_Viewer_mode = 0;
3325 static int last_Game_mode = 0;
3326 static int last_Viewer_objnum = -1;
3328 // This code is supposed to detect camera "cuts"... like going between
3331 // determine if we need to regenerate the nebula
3332 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3333 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3334 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3335 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3336 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3337 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3338 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3339 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3340 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3343 // regenerate the nebula
3347 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3348 //mprintf(( "************** Camera cut! ************\n" ));
3349 last_Viewer_mode = Viewer_mode;
3350 last_Game_mode = Game_mode;
3352 // Camera moved. Tell stars & debris to not do blurring.
3358 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3359 player_display_packlock_view();
3362 game_set_view_clip();
3364 if (Game_mode & GM_DEAD) {
3365 vector vec_to_deader, view_pos;
3368 Viewer_mode |= VM_DEAD_VIEW;
3370 if (Player_ai->target_objnum != -1) {
3371 int view_from_player = 1;
3373 if (Viewer_mode & VM_OTHER_SHIP) {
3374 // View from target.
3375 Viewer_obj = &Objects[Player_ai->target_objnum];
3377 last_Viewer_objnum = Player_ai->target_objnum;
3379 if ( Viewer_obj->type == OBJ_SHIP ) {
3380 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3381 view_from_player = 0;
3384 last_Viewer_objnum = -1;
3387 if ( view_from_player ) {
3388 // View target from player ship.
3390 *eye_pos = Player_obj->pos;
3391 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3392 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3395 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3397 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3398 dist += flFrametime * 16.0f;
3400 vm_vec_scale(&vec_to_deader, -dist);
3401 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3403 view_pos = Player_obj->pos;
3405 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3406 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3407 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3408 Dead_player_last_vel = Player_obj->phys_info.vel;
3409 //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));
3410 } else if (Player_ai->target_objnum != -1) {
3411 view_pos = Objects[Player_ai->target_objnum].pos;
3413 // Make camera follow explosion, but gradually slow down.
3414 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3415 view_pos = Player_obj->pos;
3416 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3417 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3420 *eye_pos = Dead_camera_pos;
3422 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3424 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3429 // if supernova shockwave
3430 if(supernova_camera_cut()){
3434 // call it dead view
3435 Viewer_mode |= VM_DEAD_VIEW;
3437 // set eye pos and orient
3438 supernova_set_view(eye_pos, eye_orient);
3440 // If already blown up, these other modes can override.
3441 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3442 Viewer_mode &= ~VM_DEAD_VIEW;
3444 Viewer_obj = Player_obj;
3446 if (Viewer_mode & VM_OTHER_SHIP) {
3447 if (Player_ai->target_objnum != -1){
3448 Viewer_obj = &Objects[Player_ai->target_objnum];
3449 last_Viewer_objnum = Player_ai->target_objnum;
3451 Viewer_mode &= ~VM_OTHER_SHIP;
3452 last_Viewer_objnum = -1;
3455 last_Viewer_objnum = -1;
3458 if (Viewer_mode & VM_EXTERNAL) {
3461 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3462 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3464 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3466 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3467 vm_vec_normalize(&eye_dir);
3468 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3471 // Modify the orientation based on head orientation.
3472 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3474 } else if ( Viewer_mode & VM_CHASE ) {
3477 if ( Viewer_obj->phys_info.speed < 0.1 )
3478 move_dir = Viewer_obj->orient.fvec;
3480 move_dir = Viewer_obj->phys_info.vel;
3481 vm_vec_normalize(&move_dir);
3484 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3485 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3486 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3487 vm_vec_normalize(&eye_dir);
3489 // JAS: I added the following code because if you slew up using
3490 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3491 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3492 // call because the up and the forward vector are the same. I fixed
3493 // it by adding in a fraction of the right vector all the time to the
3495 vector tmp_up = Viewer_obj->orient.uvec;
3496 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3498 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3501 // Modify the orientation based on head orientation.
3502 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3503 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3504 *eye_pos = Camera_pos;
3506 ship * shipp = &Ships[Player_obj->instance];
3508 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3509 vm_vec_normalize(&eye_dir);
3510 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3513 // get an eye position based upon the correct type of object
3514 switch(Viewer_obj->type){
3516 // make a call to get the eye point for the player object
3517 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3520 // make a call to get the eye point for the player object
3521 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3527 #ifdef JOHNS_DEBUG_CODE
3528 john_debug_stuff(&eye_pos, &eye_orient);
3534 apply_hud_shake(eye_orient);
3536 // setup neb2 rendering
3537 neb2_render_setup(eye_pos, eye_orient);
3541 extern void ai_debug_render_stuff();
3544 int Game_subspace_effect = 0;
3545 DCF_BOOL( subspace, Game_subspace_effect );
3547 // Does everything needed to render a frame
3548 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3552 g3_start_frame(game_zbuffer);
3553 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3555 // maybe offset the HUD (jitter stuff)
3556 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3557 HUD_set_offsets(Viewer_obj, !dont_offset);
3559 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3560 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3561 // must be done before ships are rendered
3562 if ( MULTIPLAYER_CLIENT ) {
3563 shield_point_multi_setup();
3566 if ( Game_subspace_effect ) {
3567 stars_draw(0,0,0,1);
3569 stars_draw(1,1,1,0);
3572 obj_render_all(obj_render);
3573 beam_render_all(); // render all beam weapons
3574 particle_render_all(); // render particles after everything else.
3575 trail_render_all(); // render missilie trails after everything else.
3576 mflash_render_all(); // render all muzzle flashes
3578 // Why do we not show the shield effect in these modes? Seems ok.
3579 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3583 // render nebula lightning
3586 // render local player nebula
3587 neb2_render_player();
3590 ai_debug_render_stuff();
3593 #ifndef RELEASE_REAL
3594 // game_framerate_check();
3598 extern void snd_spew_debug_info();
3599 snd_spew_debug_info();
3602 //================ END OF 3D RENDERING STUFF ====================
3606 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3607 hud_maybe_clear_head_area();
3608 anim_render_all(0, flFrametime);
3611 extern int Multi_display_netinfo;
3612 if(Multi_display_netinfo){
3613 extern void multi_display_netinfo();
3614 multi_display_netinfo();
3617 game_tst_frame_pre();
3620 do_timing_test(flFrametime);
3624 extern int OO_update_index;
3625 multi_rate_display(OO_update_index, 375, 0);
3630 extern void oo_display();
3637 //#define JOHNS_DEBUG_CODE 1
3639 #ifdef JOHNS_DEBUG_CODE
3640 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3642 //if ( keyd_pressed[KEY_LSHIFT] )
3644 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3646 model_subsystem *turret = tsys->system_info;
3648 if (turret->type == SUBSYSTEM_TURRET ) {
3650 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3652 ship_model_start(tobj);
3654 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3655 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3656 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3658 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3660 ship_model_stop(tobj);
3670 // following function for dumping frames for purposes of building trailers.
3673 // function to toggle state of dumping every frame into PCX when playing the game
3674 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3678 if ( Debug_dump_frames == 0 ) {
3680 Debug_dump_frames = 15;
3681 Debug_dump_trigger = 0;
3682 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3683 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3686 Debug_dump_frames = 0;
3687 Debug_dump_trigger = 0;
3688 gr_dump_frame_stop();
3689 dc_printf( "Frame dumping is now OFF\n" );
3695 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3699 if ( Debug_dump_frames == 0 ) {
3701 Debug_dump_frames = 15;
3702 Debug_dump_trigger = 1;
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_frames30, "Starts/stop frame dumping at 30 hz")
3720 if ( Debug_dump_frames == 0 ) {
3722 Debug_dump_frames = 30;
3723 Debug_dump_trigger = 0;
3724 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3725 dc_printf( "Frame dumping at 30 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_trigger, "Starts/stop frame dumping at 30 hz")
3741 if ( Debug_dump_frames == 0 ) {
3743 Debug_dump_frames = 30;
3744 Debug_dump_trigger = 1;
3745 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3746 dc_printf( "Triggered 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( "Triggered frame dumping is now OFF\n" );
3758 void game_maybe_dump_frame()
3760 if ( !Debug_dump_frames ){
3764 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3771 Debug_dump_frame_num++;
3777 extern int Player_dead_state;
3779 // Flip the page and time how long it took.
3780 void game_flip_page_and_time_it()
3784 t1 = timer_get_fixed_seconds();
3786 t2 = timer_get_fixed_seconds();
3788 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3789 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3792 void game_simulation_frame()
3794 // blow ships up in multiplayer dogfight
3795 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){
3796 // blow up all non-player ships
3797 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3800 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3802 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)){
3803 moveup = GET_NEXT(moveup);
3806 shipp = &Ships[Objects[moveup->objnum].instance];
3807 sip = &Ship_info[shipp->ship_info_index];
3809 // only blow up small ships
3810 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3811 // function to simply explode a ship where it is currently at
3812 ship_self_destruct( &Objects[moveup->objnum] );
3815 moveup = GET_NEXT(moveup);
3821 // process AWACS stuff - do this first thing
3824 // single player, set Player hits_this_frame to 0
3825 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3826 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3827 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3831 supernova_process();
3832 if(supernova_active() >= 5){
3836 // fire targeting lasers now so that
3837 // 1 - created this frame
3838 // 2 - collide this frame
3839 // 3 - render this frame
3840 // 4 - ignored and deleted next frame
3841 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3843 ship_process_targeting_lasers();
3845 // do this here so that it works for multiplayer
3847 // get viewer direction
3848 int viewer_direction = PHYSICS_VIEWER_REAR;
3850 if(Viewer_mode == 0){
3851 viewer_direction = PHYSICS_VIEWER_FRONT;
3853 if(Viewer_mode & VM_PADLOCK_UP){
3854 viewer_direction = PHYSICS_VIEWER_UP;
3856 else if(Viewer_mode & VM_PADLOCK_REAR){
3857 viewer_direction = PHYSICS_VIEWER_REAR;
3859 else if(Viewer_mode & VM_PADLOCK_LEFT){
3860 viewer_direction = PHYSICS_VIEWER_LEFT;
3862 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3863 viewer_direction = PHYSICS_VIEWER_RIGHT;
3866 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3868 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3871 #define VM_PADLOCK_UP (1 << 7)
3872 #define VM_PADLOCK_REAR (1 << 8)
3873 #define VM_PADLOCK_LEFT (1 << 9)
3874 #define VM_PADLOCK_RIGHT (1 << 10)
3876 // evaluate mission departures and arrivals before we process all objects.
3877 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3879 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3880 // ships/wing packets.
3881 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3882 mission_parse_eval_stuff();
3885 // if we're an observer, move ourselves seperately from the standard physics
3886 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3887 obj_observer_move(flFrametime);
3890 // move all the objects now
3891 obj_move_all(flFrametime);
3893 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3894 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3895 // ship_check_cargo_all();
3896 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3897 mission_eval_goals();
3901 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3902 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3903 training_check_objectives();
3906 // do all interpolation now
3907 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3908 // client side processing of warping in effect stages
3909 multi_do_client_warp(flFrametime);
3911 // client side movement of an observer
3912 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3913 obj_observer_move(flFrametime);
3916 // move all objects - does interpolation now as well
3917 obj_move_all(flFrametime);
3920 // only process the message queue when the player is "in" the game
3921 if ( !Pre_player_entry ){
3922 message_queue_process(); // process any messages send to the player
3925 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3926 message_maybe_distort(); // maybe distort incoming message if comms damaged
3927 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3928 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3929 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3932 if(!(Game_mode & GM_STANDALONE_SERVER)){
3933 // process some stuff every frame (before frame is rendered)
3934 emp_process_local();
3936 hud_update_frame(); // update hud systems
3938 if (!physics_paused) {
3939 // Move particle system
3940 particle_move_all(flFrametime);
3942 // Move missile trails
3943 trail_move_all(flFrametime);
3945 // process muzzle flashes
3946 mflash_process_all();
3948 // Flash the gun flashes
3949 shipfx_flash_do_frame(flFrametime);
3951 shockwave_move_all(flFrametime); // update all the shockwaves
3954 // subspace missile strikes
3957 obj_snd_do_frame(); // update the object-linked persistant sounds
3958 game_maybe_update_sound_environment();
3959 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3961 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3963 if ( Game_subspace_effect ) {
3964 game_start_subspace_ambient_sound();
3970 // Maybe render and process the dead-popup
3971 void game_maybe_do_dead_popup(float frametime)
3973 if ( popupdead_is_active() ) {
3975 int choice = popupdead_do_frame(frametime);
3977 if ( Game_mode & GM_NORMAL ) {
3981 if(game_do_cd_mission_check(Game_current_mission_filename)){
3982 gameseq_post_event(GS_EVENT_ENTER_GAME);
3984 gameseq_post_event(GS_EVENT_MAIN_MENU);
3989 gameseq_post_event(GS_EVENT_END_GAME);
3994 if(game_do_cd_mission_check(Game_current_mission_filename)){
3995 gameseq_post_event(GS_EVENT_START_GAME);
3997 gameseq_post_event(GS_EVENT_MAIN_MENU);
4001 // this should only happen during a red alert mission
4004 Assert(The_mission.red_alert);
4005 if(!The_mission.red_alert){
4007 if(game_do_cd_mission_check(Game_current_mission_filename)){
4008 gameseq_post_event(GS_EVENT_START_GAME);
4010 gameseq_post_event(GS_EVENT_MAIN_MENU);
4015 // choose the previous mission
4016 mission_campaign_previous_mission();
4018 if(game_do_cd_mission_check(Game_current_mission_filename)){
4019 gameseq_post_event(GS_EVENT_START_GAME);
4021 gameseq_post_event(GS_EVENT_MAIN_MENU);
4032 case POPUPDEAD_DO_MAIN_HALL:
4033 multi_quit_game(PROMPT_NONE,-1);
4036 case POPUPDEAD_DO_RESPAWN:
4037 multi_respawn_normal();
4038 event_music_player_respawn();
4041 case POPUPDEAD_DO_OBSERVER:
4042 multi_respawn_observer();
4043 event_music_player_respawn_as_observer();
4052 if ( leave_popup ) {
4058 // returns true if player is actually in a game_play stats
4059 int game_actually_playing()
4063 state = gameseq_get_state();
4064 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4070 // Draw the 2D HUD gauges
4071 void game_render_hud_2d()
4073 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4077 HUD_render_2d(flFrametime);
4081 // Draw the 3D-dependant HUD gauges
4082 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4084 g3_start_frame(0); // 0 = turn zbuffering off
4085 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4087 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4088 HUD_render_3d(flFrametime);
4092 game_sunspot_process(flFrametime);
4094 // Diminish the palette effect
4095 game_flash_diminish(flFrametime);
4103 int actually_playing;
4104 fix total_time1, total_time2;
4105 fix render2_time1=0, render2_time2=0;
4106 fix render3_time1=0, render3_time2=0;
4107 fix flip_time1=0, flip_time2=0;
4108 fix clear_time1=0, clear_time2=0;
4114 if (Framerate_delay) {
4115 int start_time = timer_get_milliseconds();
4116 while (timer_get_milliseconds() < start_time + Framerate_delay)
4122 demo_do_frame_start();
4124 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4129 // start timing frame
4130 timing_frame_start();
4132 total_time1 = timer_get_fixed_seconds();
4134 // var to hold which state we are in
4135 actually_playing = game_actually_playing();
4137 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4138 if (!(Game_mode & GM_STANDALONE_SERVER)){
4139 Assert( OBJ_INDEX(Player_obj) >= 0 );
4143 if (Missiontime > Entry_delay_time){
4144 Pre_player_entry = 0;
4146 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4149 // Note: These are done even before the player enters, else buffers can overflow.
4150 if (! (Game_mode & GM_STANDALONE_SERVER)){
4154 shield_frame_init();
4156 if ( Player->control_mode != PCM_NORMAL )
4159 if ( !Pre_player_entry && actually_playing ) {
4160 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4162 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4163 game_process_keys();
4165 // don't read flying controls if we're playing a demo back
4166 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4167 read_player_controls( Player_obj, flFrametime);
4171 // if we're not the master, we may have to send the server-critical ship status button_info bits
4172 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4173 multi_maybe_send_ship_status();
4178 // Reset the whack stuff
4181 // These two lines must be outside of Pre_player_entry code,
4182 // otherwise too many lights are added.
4185 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4189 game_simulation_frame();
4191 // if not actually in a game play state, then return. This condition could only be true in
4192 // a multiplayer game.
4193 if ( !actually_playing ) {
4194 Assert( Game_mode & GM_MULTIPLAYER );
4198 if (!Pre_player_entry) {
4199 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4200 clear_time1 = timer_get_fixed_seconds();
4201 // clear the screen to black
4203 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4207 clear_time2 = timer_get_fixed_seconds();
4208 render3_time1 = timer_get_fixed_seconds();
4209 game_render_frame_setup(&eye_pos, &eye_orient);
4210 game_render_frame( &eye_pos, &eye_orient );
4212 // save the eye position and orientation
4213 if ( Game_mode & GM_MULTIPLAYER ) {
4214 Net_player->s_info.eye_pos = eye_pos;
4215 Net_player->s_info.eye_orient = eye_orient;
4218 hud_show_target_model();
4220 // check to see if we should display the death died popup
4221 if(Game_mode & GM_DEAD_BLEW_UP){
4222 if(Game_mode & GM_MULTIPLAYER){
4223 // catch the situation where we're supposed to be warping out on this transition
4224 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4225 gameseq_post_event(GS_EVENT_DEBRIEF);
4226 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4227 Player_died_popup_wait = -1;
4231 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4232 Player_died_popup_wait = -1;
4238 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4239 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4240 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4241 if(!popupdead_is_active()){
4245 Player_multi_died_check = -1;
4249 render3_time2 = timer_get_fixed_seconds();
4250 render2_time1 = timer_get_fixed_seconds();
4253 game_get_framerate();
4254 game_show_framerate();
4256 game_show_time_left();
4258 // Draw the 2D HUD gauges
4259 if(supernova_active() < 3){
4260 game_render_hud_2d();
4263 game_set_view_clip();
4265 // Draw 3D HUD gauges
4266 game_render_hud_3d(&eye_pos, &eye_orient);
4270 render2_time2 = timer_get_fixed_seconds();
4272 // maybe render and process the dead popup
4273 game_maybe_do_dead_popup(flFrametime);
4275 // start timing frame
4276 timing_frame_stop();
4277 // timing_display(30, 10);
4279 // If a regular popup is active, don't flip (popup code flips)
4280 if( !popup_running_state() ){
4281 flip_time1 = timer_get_fixed_seconds();
4282 game_flip_page_and_time_it();
4283 flip_time2 = timer_get_fixed_seconds();
4287 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4290 game_show_standalone_framerate();
4294 game_do_training_checks();
4297 // process lightning (nebula only)
4300 total_time2 = timer_get_fixed_seconds();
4302 // Got some timing numbers
4303 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4304 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4305 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4306 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4307 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4310 demo_do_frame_end();
4312 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4318 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4319 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4320 // died. This resulted in screwed up death sequences.
4322 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4323 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4324 static int timer_paused=0;
4325 static int stop_count,start_count;
4326 static int time_stopped,time_started;
4327 int saved_timestamp_ticker = -1;
4329 void game_reset_time()
4331 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4335 // Last_time = timer_get_fixed_seconds();
4341 void game_stop_time()
4343 if (timer_paused==0) {
4345 time = timer_get_fixed_seconds();
4346 // Save how much time progressed so far in the frame so we can
4347 // use it when we unpause.
4348 Last_delta_time = time - Last_time;
4350 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4351 if (Last_delta_time < 0) {
4352 #if defined(TIMER_TEST) && !defined(NDEBUG)
4353 Int3(); //get Matt!!!!
4355 Last_delta_time = 0;
4357 #if defined(TIMER_TEST) && !defined(NDEBUG)
4358 time_stopped = time;
4361 // Stop the timer_tick stuff...
4362 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4363 saved_timestamp_ticker = timestamp_ticker;
4367 #if defined(TIMER_TEST) && !defined(NDEBUG)
4372 void game_start_time()
4375 Assert(timer_paused >= 0);
4376 if (timer_paused==0) {
4378 time = timer_get_fixed_seconds();
4379 #if defined(TIMER_TEST) && !defined(NDEBUG)
4381 Int3(); //get Matt!!!!
4384 // Take current time, and set it backwards to account for time
4385 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4386 // will be correct when it goes to calculate the frametime next
4388 Last_time = time - Last_delta_time;
4389 #if defined(TIMER_TEST) && !defined(NDEBUG)
4390 time_started = time;
4393 // Restore the timer_tick stuff...
4394 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4395 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4396 timestamp_ticker = saved_timestamp_ticker;
4397 saved_timestamp_ticker = -1;
4400 #if defined(TIMER_TEST) && !defined(NDEBUG)
4406 void game_set_frametime(int state)
4409 float frame_cap_diff;
4411 thistime = timer_get_fixed_seconds();
4413 if ( Last_time == 0 )
4414 Frametime = F1_0 / 30;
4416 Frametime = thistime - Last_time;
4418 // Frametime = F1_0 / 30;
4420 fix debug_frametime = Frametime; // Just used to display frametime.
4422 // If player hasn't entered mission yet, make frame take 1/4 second.
4423 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4426 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4428 fix frame_speed = F1_0 / Debug_dump_frames;
4430 if (Frametime > frame_speed ){
4431 nprintf(("warning","slow frame: %x\n",Frametime));
4434 thistime = timer_get_fixed_seconds();
4435 Frametime = thistime - Last_time;
4436 } while (Frametime < frame_speed );
4438 Frametime = frame_speed;
4442 Assert( Framerate_cap > 0 );
4444 // Cap the framerate so it doesn't get too high.
4448 cap = F1_0/Framerate_cap;
4449 if (Frametime < cap) {
4450 thistime = cap - Frametime;
4451 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4452 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4454 thistime = timer_get_fixed_seconds();
4458 if((Game_mode & GM_STANDALONE_SERVER) &&
4459 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4461 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4462 Sleep((DWORD)(frame_cap_diff*1000));
4464 thistime += fl2f((frame_cap_diff));
4466 Frametime = thistime - Last_time;
4469 // If framerate is too low, cap it.
4470 if (Frametime > MAX_FRAMETIME) {
4472 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4474 // to remove warnings in release build
4475 debug_frametime = fl2f(flFrametime);
4477 Frametime = MAX_FRAMETIME;
4480 Frametime = fixmul(Frametime, Game_time_compression);
4482 Last_time = thistime;
4483 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4485 flFrametime = f2fl(Frametime);
4486 //if(!(Game_mode & GM_PLAYING_DEMO)){
4487 timestamp_inc(flFrametime);
4489 /* if ((Framecount > 0) && (Framecount < 10)) {
4490 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4495 // This is called from game_do_frame(), and from navmap_do_frame()
4496 void game_update_missiontime()
4498 // TODO JAS: Put in if and move this into game_set_frametime,
4499 // fix navmap to call game_stop/start_time
4500 //if ( !timer_paused )
4501 Missiontime += Frametime;
4504 void game_do_frame()
4506 game_set_frametime(GS_STATE_GAME_PLAY);
4507 game_update_missiontime();
4509 if (Game_mode & GM_STANDALONE_SERVER) {
4510 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4513 if ( game_single_step && (last_single_step == game_single_step) ) {
4514 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4515 while( key_checkch() == 0 )
4517 os_set_title( XSTR( "FreeSpace", 171) );
4518 Last_time = timer_get_fixed_seconds();
4521 last_single_step = game_single_step;
4523 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4524 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4528 Keep_mouse_centered = 0;
4529 monitor_update(); // Update monitor variables
4532 void multi_maybe_do_frame()
4534 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4539 int Joymouse_button_status = 0;
4541 // Flush all input devices
4549 Joymouse_button_status = 0;
4551 //mprintf(("Game flush!\n" ));
4554 // function for multiplayer only which calls game_do_state_common() when running the
4556 void game_do_dc_networking()
4558 Assert( Game_mode & GM_MULTIPLAYER );
4560 game_do_state_common( gameseq_get_state() );
4563 // Call this whenever in a loop, or when you need to check for a keystroke.
4564 int game_check_key()
4570 // convert keypad enter to normal enter
4571 if ((k & KEY_MASK) == KEY_PADENTER)
4572 k = (k & ~KEY_MASK) | KEY_ENTER;
4579 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4580 static int Demo_show_trailer_timestamp = 0;
4582 void demo_reset_trailer_timer()
4584 Demo_show_trailer_timestamp = timer_get_milliseconds();
4587 void demo_maybe_show_trailer(int k)
4590 // if key pressed, reset demo trailer timer
4592 demo_reset_trailer_timer();
4596 // if mouse moved, reset demo trailer timer
4599 mouse_get_delta(&dx, &dy);
4600 if ( (dx > 0) || (dy > 0) ) {
4601 demo_reset_trailer_timer();
4605 // if joystick has moved, reset demo trailer timer
4608 joy_get_delta(&dx, &dy);
4609 if ( (dx > 0) || (dy > 0) ) {
4610 demo_reset_trailer_timer();
4614 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4615 // the low-level code. Ugly, I know... but was the simplest and most
4618 // if 30 seconds since last demo trailer time reset, launch movie
4619 if ( os_foreground() ) {
4620 int now = timer_get_milliseconds();
4621 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4622 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4624 movie_play( NOX("fstrailer2.mve") );
4625 demo_reset_trailer_timer();
4633 // same as game_check_key(), except this is used while actually in the game. Since there
4634 // generally are differences between game control keys and general UI keys, makes sense to
4635 // have seperate functions for each case. If you are not checking a game control while in a
4636 // mission, you should probably be using game_check_key() instead.
4641 if (!os_foreground()) {
4646 // If we're in a single player game, pause it.
4647 if (!(Game_mode & GM_MULTIPLAYER)){
4648 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4649 game_process_pause_key();
4657 demo_maybe_show_trailer(k);
4660 // Move the mouse cursor with the joystick.
4661 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4662 // Move the mouse cursor with the joystick
4666 joy_get_pos( &jx, &jy, &jz, &jr );
4668 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4669 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4672 mouse_get_real_pos( &mx, &my );
4673 mouse_set_pos( mx+dx, my+dy );
4678 m = mouse_down(MOUSE_LEFT_BUTTON);
4680 if ( j != Joymouse_button_status ) {
4681 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4682 Joymouse_button_status = j;
4684 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4685 } else if ( (!j) && (m) ) {
4686 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4691 // if we should be ignoring keys because of some multiplayer situations
4692 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4696 // If a popup is running, don't process all the Fn keys
4697 if( popup_active() ) {
4701 state = gameseq_get_state();
4703 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4706 case KEY_DEBUGGED + KEY_BACKSP:
4711 launch_context_help();
4716 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4718 // don't allow f2 while warping out in multiplayer
4719 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4724 case GS_STATE_INITIAL_PLAYER_SELECT:
4725 case GS_STATE_OPTIONS_MENU:
4726 case GS_STATE_HUD_CONFIG:
4727 case GS_STATE_CONTROL_CONFIG:
4728 case GS_STATE_DEATH_DIED:
4729 case GS_STATE_DEATH_BLEW_UP:
4730 case GS_STATE_VIEW_MEDALS:
4734 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4741 // hotkey selection screen -- only valid from briefing and beyond.
4744 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) ) {
4745 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4751 case KEY_DEBUGGED + KEY_F3:
4752 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4755 case KEY_DEBUGGED + KEY_F4:
4756 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4760 if(Game_mode & GM_MULTIPLAYER){
4761 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4762 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4766 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4767 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4773 case KEY_ESC | KEY_SHIFTED:
4774 // make sure to quit properly out of multiplayer
4775 if(Game_mode & GM_MULTIPLAYER){
4776 multi_quit_game(PROMPT_NONE);
4779 gameseq_post_event( GS_EVENT_QUIT_GAME );
4784 case KEY_DEBUGGED + KEY_P:
4787 case KEY_PRINT_SCRN:
4789 static int counter = 0;
4794 sprintf( tmp_name, NOX("screen%02d"), counter );
4796 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4797 gr_print_screen(tmp_name);
4805 case KEY_SHIFTED | KEY_ENTER: {
4807 #if !defined(NDEBUG)
4809 if ( Game_mode & GM_NORMAL ){
4813 // if we're in multiplayer mode, do some special networking
4814 if(Game_mode & GM_MULTIPLAYER){
4815 debug_console(game_do_dc_networking);
4822 if ( Game_mode & GM_NORMAL )
4836 gameseq_post_event(GS_EVENT_QUIT_GAME);
4839 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4842 void camera_set_position( vector *pos )
4847 void camera_set_orient( matrix *orient )
4849 Camera_orient = *orient;
4852 void camera_set_velocity( vector *vel, int instantaneous )
4854 Camera_desired_velocity.x = 0.0f;
4855 Camera_desired_velocity.y = 0.0f;
4856 Camera_desired_velocity.z = 0.0f;
4858 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4859 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4860 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4862 if ( instantaneous ) {
4863 Camera_velocity = Camera_desired_velocity;
4871 vector new_vel, delta_pos;
4873 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4874 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4875 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4877 Camera_velocity = new_vel;
4879 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4881 vm_vec_add2( &Camera_pos, &delta_pos );
4883 float ot = Camera_time+0.0f;
4885 Camera_time += flFrametime;
4887 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4890 tmp.z = 4.739f; // always go this fast forward.
4892 // pick x and y velocities so they are always on a
4893 // circle with a 25 m radius.
4895 float tmp_angle = frand()*PI2;
4897 tmp.x = 22.0f * (float)sin(tmp_angle);
4898 tmp.y = -22.0f * (float)cos(tmp_angle);
4900 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4902 //mprintf(( "Changing velocity!\n" ));
4903 camera_set_velocity( &tmp, 0 );
4906 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4907 vector tmp = { 0.0f, 0.0f, 0.0f };
4908 camera_set_velocity( &tmp, 0 );
4913 void end_demo_campaign_do()
4915 #if defined(FS2_DEMO)
4916 // show upsell screens
4917 demo_upsell_show_screens();
4918 #elif defined(OEM_BUILD)
4919 // show oem upsell screens
4920 oem_upsell_show_screens();
4923 // drop into main hall
4924 gameseq_post_event( GS_EVENT_MAIN_MENU );
4927 // All code to process events. This is the only place
4928 // that you should change the state of the game.
4929 void game_process_event( int current_state, int event )
4931 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4934 case GS_EVENT_SIMULATOR_ROOM:
4935 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4938 case GS_EVENT_MAIN_MENU:
4939 gameseq_set_state(GS_STATE_MAIN_MENU);
4942 case GS_EVENT_OPTIONS_MENU:
4943 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4946 case GS_EVENT_BARRACKS_MENU:
4947 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4950 case GS_EVENT_TECH_MENU:
4951 gameseq_set_state(GS_STATE_TECH_MENU);
4954 case GS_EVENT_TRAINING_MENU:
4955 gameseq_set_state(GS_STATE_TRAINING_MENU);
4958 case GS_EVENT_START_GAME:
4959 Select_default_ship = 0;
4960 Player_multi_died_check = -1;
4961 gameseq_set_state(GS_STATE_CMD_BRIEF);
4964 case GS_EVENT_START_BRIEFING:
4965 gameseq_set_state(GS_STATE_BRIEFING);
4968 case GS_EVENT_DEBRIEF:
4969 // did we end the campaign in the main freespace 2 single player campaign?
4970 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4971 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4973 gameseq_set_state(GS_STATE_DEBRIEF);
4976 Player_multi_died_check = -1;
4979 case GS_EVENT_SHIP_SELECTION:
4980 gameseq_set_state( GS_STATE_SHIP_SELECT );
4983 case GS_EVENT_WEAPON_SELECTION:
4984 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4987 case GS_EVENT_ENTER_GAME:
4989 // maybe start recording a demo
4991 demo_start_record("test.fsd");
4995 if (Game_mode & GM_MULTIPLAYER) {
4996 // if we're respawning, make sure we change the view mode so that the hud shows up
4997 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5001 gameseq_set_state(GS_STATE_GAME_PLAY);
5003 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5006 Player_multi_died_check = -1;
5008 // clear multiplayer button info
5009 extern button_info Multi_ship_status_bi;
5010 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5012 Start_time = f2fl(timer_get_approx_seconds());
5014 mprintf(("Entering game at time = %7.3f\n", Start_time));
5018 case GS_EVENT_START_GAME_QUICK:
5019 Select_default_ship = 1;
5020 gameseq_post_event(GS_EVENT_ENTER_GAME);
5024 case GS_EVENT_END_GAME:
5025 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5026 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5027 gameseq_set_state(GS_STATE_MAIN_MENU);
5032 Player_multi_died_check = -1;
5035 case GS_EVENT_QUIT_GAME:
5036 main_hall_stop_music();
5037 main_hall_stop_ambient();
5038 gameseq_set_state(GS_STATE_QUIT_GAME);
5040 Player_multi_died_check = -1;
5043 case GS_EVENT_GAMEPLAY_HELP:
5044 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5047 case GS_EVENT_PAUSE_GAME:
5048 gameseq_push_state(GS_STATE_GAME_PAUSED);
5051 case GS_EVENT_DEBUG_PAUSE_GAME:
5052 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5055 case GS_EVENT_TRAINING_PAUSE:
5056 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5059 case GS_EVENT_PREVIOUS_STATE:
5060 gameseq_pop_state();
5063 case GS_EVENT_TOGGLE_FULLSCREEN:
5064 #ifndef HARDWARE_ONLY
5066 if ( gr_screen.mode == GR_SOFTWARE ) {
5067 gr_init( GR_640, GR_DIRECTDRAW );
5068 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5069 gr_init( GR_640, GR_SOFTWARE );
5075 case GS_EVENT_TOGGLE_GLIDE:
5077 if ( gr_screen.mode != GR_GLIDE ) {
5078 gr_init( GR_640, GR_GLIDE );
5080 gr_init( GR_640, GR_SOFTWARE );
5085 case GS_EVENT_LOAD_MISSION_MENU:
5086 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5089 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5090 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5093 case GS_EVENT_HUD_CONFIG:
5094 gameseq_push_state( GS_STATE_HUD_CONFIG );
5097 case GS_EVENT_CONTROL_CONFIG:
5098 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5101 case GS_EVENT_DEATH_DIED:
5102 gameseq_set_state( GS_STATE_DEATH_DIED );
5105 case GS_EVENT_DEATH_BLEW_UP:
5106 if ( current_state == GS_STATE_DEATH_DIED ) {
5107 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5108 event_music_player_death();
5110 // multiplayer clients set their extra check here
5111 if(Game_mode & GM_MULTIPLAYER){
5112 // set the multi died absolute last chance check
5113 Player_multi_died_check = time(NULL);
5116 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5120 case GS_EVENT_NEW_CAMPAIGN:
5121 if (!mission_load_up_campaign()){
5122 readyroom_continue_campaign();
5125 Player_multi_died_check = -1;
5128 case GS_EVENT_CAMPAIGN_CHEAT:
5129 if (!mission_load_up_campaign()){
5131 // bash campaign value
5132 extern char Main_hall_campaign_cheat[512];
5135 // look for the mission
5136 for(idx=0; idx<Campaign.num_missions; idx++){
5137 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5138 Campaign.next_mission = idx;
5139 Campaign.prev_mission = idx - 1;
5146 readyroom_continue_campaign();
5149 Player_multi_died_check = -1;
5152 case GS_EVENT_CAMPAIGN_ROOM:
5153 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5156 case GS_EVENT_CMD_BRIEF:
5157 gameseq_set_state(GS_STATE_CMD_BRIEF);
5160 case GS_EVENT_RED_ALERT:
5161 gameseq_set_state(GS_STATE_RED_ALERT);
5164 case GS_EVENT_CREDITS:
5165 gameseq_set_state( GS_STATE_CREDITS );
5168 case GS_EVENT_VIEW_MEDALS:
5169 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5172 case GS_EVENT_SHOW_GOALS:
5173 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5176 case GS_EVENT_HOTKEY_SCREEN:
5177 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5180 // multiplayer stuff follow these comments
5182 case GS_EVENT_MULTI_JOIN_GAME:
5183 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5186 case GS_EVENT_MULTI_HOST_SETUP:
5187 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5190 case GS_EVENT_MULTI_CLIENT_SETUP:
5191 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5194 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5195 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5198 case GS_EVENT_MULTI_STD_WAIT:
5199 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5202 case GS_EVENT_STANDALONE_MAIN:
5203 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5206 case GS_EVENT_MULTI_PAUSE:
5207 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5210 case GS_EVENT_INGAME_PRE_JOIN:
5211 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5214 case GS_EVENT_EVENT_DEBUG:
5215 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5218 // Start a warpout where player automatically goes 70 no matter what
5219 // and can't cancel out of it.
5220 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5221 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5223 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5224 Player->saved_viewer_mode = Viewer_mode;
5225 Player->control_mode = PCM_WARPOUT_STAGE1;
5226 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5227 Warpout_time = 0.0f; // Start timer!
5230 case GS_EVENT_PLAYER_WARPOUT_START:
5231 if ( Player->control_mode != PCM_NORMAL ) {
5232 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5234 Player->saved_viewer_mode = Viewer_mode;
5235 Player->control_mode = PCM_WARPOUT_STAGE1;
5236 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5237 Warpout_time = 0.0f; // Start timer!
5238 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5242 case GS_EVENT_PLAYER_WARPOUT_STOP:
5243 if ( Player->control_mode != PCM_NORMAL ) {
5244 if ( !Warpout_forced ) { // cannot cancel forced warpout
5245 Player->control_mode = PCM_NORMAL;
5246 Viewer_mode = Player->saved_viewer_mode;
5247 hud_subspace_notify_abort();
5248 mprintf(( "Player put back to normal mode.\n" ));
5249 if ( Warpout_sound > -1 ) {
5250 snd_stop( Warpout_sound );
5257 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5258 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5259 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5260 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5262 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5263 shipfx_warpout_start( Player_obj );
5264 Player->control_mode = PCM_WARPOUT_STAGE2;
5265 Player->saved_viewer_mode = Viewer_mode;
5266 Viewer_mode |= VM_WARP_CHASE;
5268 vector tmp = Player_obj->pos;
5270 ship_get_eye( &tmp, &tmp_m, Player_obj );
5271 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5272 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5273 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5275 camera_set_position( &tmp );
5276 camera_set_orient( &Player_obj->orient );
5277 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5279 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5280 camera_set_velocity( &tmp_vel, 1);
5284 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5285 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5286 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5287 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5289 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5290 Player->control_mode = PCM_WARPOUT_STAGE3;
5294 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5295 mprintf(( "Player warped out. Going to debriefing!\n" ));
5296 Player->control_mode = PCM_NORMAL;
5297 Viewer_mode = Player->saved_viewer_mode;
5300 // we have a special debriefing screen for multiplayer furballs
5301 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5302 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5304 // do the normal debriefing for all other situations
5306 gameseq_post_event(GS_EVENT_DEBRIEF);
5310 case GS_EVENT_STANDALONE_POSTGAME:
5311 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5314 case GS_EVENT_INITIAL_PLAYER_SELECT:
5315 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5318 case GS_EVENT_GAME_INIT:
5319 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5320 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5322 // see if the command line option has been set to use the last pilot, and act acoordingly
5323 if( player_select_get_last_pilot() ) {
5324 // always enter the main menu -- do the automatic network startup stuff elsewhere
5325 // so that we still have valid checks for networking modes, etc.
5326 gameseq_set_state(GS_STATE_MAIN_MENU);
5328 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5333 case GS_EVENT_MULTI_MISSION_SYNC:
5334 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5337 case GS_EVENT_MULTI_START_GAME:
5338 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5341 case GS_EVENT_MULTI_HOST_OPTIONS:
5342 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5345 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5346 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5349 case GS_EVENT_TEAM_SELECT:
5350 gameseq_set_state(GS_STATE_TEAM_SELECT);
5353 case GS_EVENT_END_CAMPAIGN:
5354 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5357 case GS_EVENT_END_DEMO:
5358 gameseq_set_state(GS_STATE_END_DEMO);
5361 case GS_EVENT_LOOP_BRIEF:
5362 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5371 // Called when a state is being left.
5372 // The current state is still at old_state, but as soon as
5373 // this function leaves, then the current state will become
5374 // new state. You should never try to change the state
5375 // in here... if you think you need to, you probably really
5376 // need to post an event, not change the state.
5377 void game_leave_state( int old_state, int new_state )
5379 int end_mission = 1;
5381 switch (new_state) {
5382 case GS_STATE_GAME_PAUSED:
5383 case GS_STATE_DEBUG_PAUSED:
5384 case GS_STATE_OPTIONS_MENU:
5385 case GS_STATE_CONTROL_CONFIG:
5386 case GS_STATE_MISSION_LOG_SCROLLBACK:
5387 case GS_STATE_DEATH_DIED:
5388 case GS_STATE_SHOW_GOALS:
5389 case GS_STATE_HOTKEY_SCREEN:
5390 case GS_STATE_MULTI_PAUSED:
5391 case GS_STATE_TRAINING_PAUSED:
5392 case GS_STATE_EVENT_DEBUG:
5393 case GS_STATE_GAMEPLAY_HELP:
5394 end_mission = 0; // these events shouldn't end a mission
5398 switch (old_state) {
5399 case GS_STATE_BRIEFING:
5400 brief_stop_voices();
5401 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5402 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5403 && (new_state != GS_STATE_TEAM_SELECT) ){
5404 common_select_close();
5405 if ( new_state == GS_STATE_MAIN_MENU ) {
5406 freespace_stop_mission();
5410 // COMMAND LINE OPTION
5411 if (Cmdline_multi_stream_chat_to_file){
5412 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5413 cfclose(Multi_chat_stream);
5417 case GS_STATE_DEBRIEF:
5418 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5423 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5424 multi_df_debrief_close();
5427 case GS_STATE_LOAD_MISSION_MENU:
5428 mission_load_menu_close();
5431 case GS_STATE_SIMULATOR_ROOM:
5435 case GS_STATE_CAMPAIGN_ROOM:
5436 campaign_room_close();
5439 case GS_STATE_CMD_BRIEF:
5440 if (new_state == GS_STATE_OPTIONS_MENU) {
5445 if (new_state == GS_STATE_MAIN_MENU)
5446 freespace_stop_mission();
5451 case GS_STATE_RED_ALERT:
5455 case GS_STATE_SHIP_SELECT:
5456 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5457 new_state != GS_STATE_HOTKEY_SCREEN &&
5458 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5459 common_select_close();
5460 if ( new_state == GS_STATE_MAIN_MENU ) {
5461 freespace_stop_mission();
5466 case GS_STATE_WEAPON_SELECT:
5467 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5468 new_state != GS_STATE_HOTKEY_SCREEN &&
5469 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5470 common_select_close();
5471 if ( new_state == GS_STATE_MAIN_MENU ) {
5472 freespace_stop_mission();
5477 case GS_STATE_TEAM_SELECT:
5478 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5479 new_state != GS_STATE_HOTKEY_SCREEN &&
5480 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5481 common_select_close();
5482 if ( new_state == GS_STATE_MAIN_MENU ) {
5483 freespace_stop_mission();
5488 case GS_STATE_MAIN_MENU:
5489 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5496 case GS_STATE_OPTIONS_MENU:
5497 //game_start_time();
5498 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5499 multi_join_clear_game_list();
5501 options_menu_close();
5504 case GS_STATE_BARRACKS_MENU:
5505 if(new_state != GS_STATE_VIEW_MEDALS){
5510 case GS_STATE_MISSION_LOG_SCROLLBACK:
5511 hud_scrollback_close();
5514 case GS_STATE_TRAINING_MENU:
5515 training_menu_close();
5518 case GS_STATE_GAME_PLAY:
5519 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5520 player_save_target_and_weapon_link_prefs();
5521 game_stop_looped_sounds();
5524 sound_env_disable();
5525 joy_ff_stop_effects();
5527 // stop game time under certain conditions
5528 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5533 // shut down any recording or playing demos
5538 // when in multiplayer and going back to the main menu, send a leave game packet
5539 // right away (before calling stop mission). stop_mission was taking to long to
5540 // close mission down and I want people to get notified ASAP.
5541 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5542 multi_quit_game(PROMPT_NONE);
5545 freespace_stop_mission();
5546 Game_time_compression = F1_0;
5550 case GS_STATE_TECH_MENU:
5554 case GS_STATE_TRAINING_PAUSED:
5555 Training_num_lines = 0;
5556 // fall through to GS_STATE_GAME_PAUSED
5558 case GS_STATE_GAME_PAUSED:
5560 if ( end_mission ) {
5565 case GS_STATE_DEBUG_PAUSED:
5568 pause_debug_close();
5572 case GS_STATE_HUD_CONFIG:
5576 // join/start a game
5577 case GS_STATE_MULTI_JOIN_GAME:
5578 if(new_state != GS_STATE_OPTIONS_MENU){
5579 multi_join_game_close();
5583 case GS_STATE_MULTI_HOST_SETUP:
5584 case GS_STATE_MULTI_CLIENT_SETUP:
5585 // if this is just the host going into the options screen, don't do anything
5586 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5590 // close down the proper state
5591 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5592 multi_create_game_close();
5594 multi_game_client_setup_close();
5597 // COMMAND LINE OPTION
5598 if (Cmdline_multi_stream_chat_to_file){
5599 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5600 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5601 cfclose(Multi_chat_stream);
5606 case GS_STATE_CONTROL_CONFIG:
5607 control_config_close();
5610 case GS_STATE_DEATH_DIED:
5611 Game_mode &= ~GM_DEAD_DIED;
5613 // early end while respawning or blowing up in a multiplayer game
5614 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5616 freespace_stop_mission();
5620 case GS_STATE_DEATH_BLEW_UP:
5621 Game_mode &= ~GM_DEAD_BLEW_UP;
5623 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5624 // to determine if I should do anything.
5625 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5627 freespace_stop_mission();
5630 // if we are not respawing as an observer or as a player, our new state will not
5631 // be gameplay state.
5632 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5633 game_stop_time(); // hasn't been called yet!!
5634 freespace_stop_mission();
5640 case GS_STATE_CREDITS:
5644 case GS_STATE_VIEW_MEDALS:
5648 case GS_STATE_SHOW_GOALS:
5649 mission_show_goals_close();
5652 case GS_STATE_HOTKEY_SCREEN:
5653 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5654 mission_hotkey_close();
5658 case GS_STATE_MULTI_MISSION_SYNC:
5659 // if we're moving into the options menu, don't do anything
5660 if(new_state == GS_STATE_OPTIONS_MENU){
5664 Assert( Game_mode & GM_MULTIPLAYER );
5666 if ( new_state == GS_STATE_GAME_PLAY ){
5667 // palette_restore_palette();
5669 // change a couple of flags to indicate our state!!!
5670 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5671 send_netplayer_update_packet();
5673 // set the game mode
5674 Game_mode |= GM_IN_MISSION;
5678 case GS_STATE_VIEW_CUTSCENES:
5679 cutscenes_screen_close();
5682 case GS_STATE_MULTI_STD_WAIT:
5683 multi_standalone_wait_close();
5686 case GS_STATE_STANDALONE_MAIN:
5687 standalone_main_close();
5688 if(new_state == GS_STATE_MULTI_STD_WAIT){
5689 init_multiplayer_stats();
5693 case GS_STATE_MULTI_PAUSED:
5694 // if ( end_mission ){
5699 case GS_STATE_INGAME_PRE_JOIN:
5700 multi_ingame_select_close();
5703 case GS_STATE_STANDALONE_POSTGAME:
5704 multi_standalone_postgame_close();
5707 case GS_STATE_INITIAL_PLAYER_SELECT:
5708 player_select_close();
5711 case GS_STATE_MULTI_START_GAME:
5712 multi_start_game_close();
5715 case GS_STATE_MULTI_HOST_OPTIONS:
5716 multi_host_options_close();
5719 case GS_STATE_END_OF_CAMPAIGN:
5720 mission_campaign_end_close();
5723 case GS_STATE_LOOP_BRIEF:
5729 // Called when a state is being entered.
5730 // The current state is set to the state we're entering at
5731 // this point, and old_state is set to the state we're coming
5732 // from. You should never try to change the state
5733 // in here... if you think you need to, you probably really
5734 // need to post an event, not change the state.
5736 void game_enter_state( int old_state, int new_state )
5738 switch (new_state) {
5739 case GS_STATE_MAIN_MENU:
5740 // in multiplayer mode, be sure that we are not doing networking anymore.
5741 if ( Game_mode & GM_MULTIPLAYER ) {
5742 Assert( Net_player != NULL );
5743 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5746 Game_time_compression = F1_0;
5748 // determine which ship this guy is currently based on
5749 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5752 if (Player->on_bastion) {
5760 case GS_STATE_BRIEFING:
5761 main_hall_stop_music();
5762 main_hall_stop_ambient();
5764 if (Game_mode & GM_NORMAL) {
5765 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5766 // MWA: or from options or hotkey screens
5767 // JH: or if the command brief state already did this
5768 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5769 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5770 && (old_state != GS_STATE_CMD_BRIEF) ) {
5771 if ( !game_start_mission() ) // this should put us into a new state on failure!
5775 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5776 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5777 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5779 Game_time_compression = F1_0;
5781 if ( red_alert_mission() ) {
5782 gameseq_post_event(GS_EVENT_RED_ALERT);
5789 case GS_STATE_DEBRIEF:
5790 game_stop_looped_sounds();
5791 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5792 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5797 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5798 multi_df_debrief_init();
5801 case GS_STATE_LOAD_MISSION_MENU:
5802 mission_load_menu_init();
5805 case GS_STATE_SIMULATOR_ROOM:
5809 case GS_STATE_CAMPAIGN_ROOM:
5810 campaign_room_init();
5813 case GS_STATE_RED_ALERT:
5814 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5818 case GS_STATE_CMD_BRIEF: {
5819 int team_num = 0; // team number used as index for which cmd brief to use.
5821 if (old_state == GS_STATE_OPTIONS_MENU) {
5825 main_hall_stop_music();
5826 main_hall_stop_ambient();
5828 if (Game_mode & GM_NORMAL) {
5829 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5830 // MWA: or from options or hotkey screens
5831 // JH: or if the command brief state already did this
5832 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5833 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5834 if ( !game_start_mission() ) // this should put us into a new state on failure!
5839 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5840 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5841 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5843 cmd_brief_init(team_num);
5849 case GS_STATE_SHIP_SELECT:
5853 case GS_STATE_WEAPON_SELECT:
5854 weapon_select_init();
5857 case GS_STATE_TEAM_SELECT:
5861 case GS_STATE_GAME_PAUSED:
5866 case GS_STATE_DEBUG_PAUSED:
5867 // game_stop_time();
5868 // os_set_title("FreeSpace - PAUSED");
5871 case GS_STATE_TRAINING_PAUSED:
5878 case GS_STATE_OPTIONS_MENU:
5880 options_menu_init();
5883 case GS_STATE_GAME_PLAY:
5884 // coming from the gameplay state or the main menu, we might need to load the mission
5885 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5886 if ( !game_start_mission() ) // this should put us into a new state.
5891 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5892 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5893 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5894 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5895 (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) ) {
5896 // JAS: Used to do all paging here.
5900 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5904 main_hall_stop_music();
5905 main_hall_stop_ambient();
5906 event_music_first_pattern(); // start the first pattern
5909 // special code that restores player ship selection and weapons loadout when doing a quick start
5910 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5911 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5912 wss_direct_restore_loadout();
5916 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5917 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5918 event_music_first_pattern(); // start the first pattern
5921 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5922 event_music_first_pattern(); // start the first pattern
5924 player_restore_target_and_weapon_link_prefs();
5926 Game_mode |= GM_IN_MISSION;
5929 // required to truely make mouse deltas zeroed in debug mouse code
5930 void mouse_force_pos(int x, int y);
5931 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5936 // only start time if in single player, or coming from multi wait state
5939 (Game_mode & GM_NORMAL) &&
5940 (old_state != GS_STATE_VIEW_CUTSCENES)
5942 (Game_mode & GM_MULTIPLAYER) && (
5943 (old_state == GS_STATE_MULTI_PAUSED) ||
5944 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5950 // when coming from the multi paused state, reset the timestamps
5951 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5952 multi_reset_timestamps();
5955 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5956 // initialize all object update details
5957 multi_oo_gameplay_init();
5960 // under certain circumstances, the server should reset the object update rate limiting stuff
5961 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5962 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5964 // reinitialize the rate limiting system for all clients
5965 multi_oo_rate_init_all();
5968 // multiplayer clients should always re-initialize their control info rate limiting system
5969 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5970 multi_oo_rate_init_all();
5974 if(Game_mode & GM_MULTIPLAYER){
5975 multi_ping_reset_players();
5978 Game_subspace_effect = 0;
5979 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5980 Game_subspace_effect = 1;
5981 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5982 game_start_subspace_ambient_sound();
5986 sound_env_set(&Game_sound_env);
5987 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5989 // clear multiplayer button info i
5990 extern button_info Multi_ship_status_bi;
5991 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5994 case GS_STATE_HUD_CONFIG:
5998 case GS_STATE_MULTI_JOIN_GAME:
5999 multi_join_clear_game_list();
6001 if (old_state != GS_STATE_OPTIONS_MENU) {
6002 multi_join_game_init();
6007 case GS_STATE_MULTI_HOST_SETUP:
6008 // don't reinitialize if we're coming back from the host options screen
6009 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6010 multi_create_game_init();
6015 case GS_STATE_MULTI_CLIENT_SETUP:
6016 if (old_state != GS_STATE_OPTIONS_MENU) {
6017 multi_game_client_setup_init();
6022 case GS_STATE_CONTROL_CONFIG:
6023 control_config_init();
6026 case GS_STATE_TECH_MENU:
6030 case GS_STATE_BARRACKS_MENU:
6031 if(old_state != GS_STATE_VIEW_MEDALS){
6036 case GS_STATE_MISSION_LOG_SCROLLBACK:
6037 hud_scrollback_init();
6040 case GS_STATE_DEATH_DIED:
6041 Player_died_time = timestamp(10);
6043 if(!(Game_mode & GM_MULTIPLAYER)){
6044 player_show_death_message();
6046 Game_mode |= GM_DEAD_DIED;
6049 case GS_STATE_DEATH_BLEW_UP:
6050 if ( !popupdead_is_active() ) {
6051 Player_ai->target_objnum = -1;
6054 // stop any local EMP effect
6057 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6058 Game_mode |= GM_DEAD_BLEW_UP;
6059 Show_viewing_from_self = 0;
6061 // timestamp how long we should wait before displaying the died popup
6062 if ( !popupdead_is_active() ) {
6063 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6067 case GS_STATE_GAMEPLAY_HELP:
6068 gameplay_help_init();
6071 case GS_STATE_CREDITS:
6072 main_hall_stop_music();
6073 main_hall_stop_ambient();
6077 case GS_STATE_VIEW_MEDALS:
6078 medal_main_init(Player);
6081 case GS_STATE_SHOW_GOALS:
6082 mission_show_goals_init();
6085 case GS_STATE_HOTKEY_SCREEN:
6086 mission_hotkey_init();
6089 case GS_STATE_MULTI_MISSION_SYNC:
6090 // if we're coming from the options screen, don't do any
6091 if(old_state == GS_STATE_OPTIONS_MENU){
6095 switch(Multi_sync_mode){
6096 case MULTI_SYNC_PRE_BRIEFING:
6097 // if moving from game forming to the team select state
6100 case MULTI_SYNC_POST_BRIEFING:
6101 // if moving from briefing into the mission itself
6104 // tell everyone that we're now loading data
6105 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6106 send_netplayer_update_packet();
6108 // JAS: Used to do all paging here!!!!
6110 Net_player->state = NETPLAYER_STATE_WAITING;
6111 send_netplayer_update_packet();
6113 Game_time_compression = F1_0;
6115 case MULTI_SYNC_INGAME:
6121 case GS_STATE_VIEW_CUTSCENES:
6122 cutscenes_screen_init();
6125 case GS_STATE_MULTI_STD_WAIT:
6126 multi_standalone_wait_init();
6129 case GS_STATE_STANDALONE_MAIN:
6130 // don't initialize if we're coming from one of these 2 states unless there are no
6131 // players left (reset situation)
6132 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6133 standalone_main_init();
6137 case GS_STATE_MULTI_PAUSED:
6141 case GS_STATE_INGAME_PRE_JOIN:
6142 multi_ingame_select_init();
6145 case GS_STATE_STANDALONE_POSTGAME:
6146 multi_standalone_postgame_init();
6149 case GS_STATE_INITIAL_PLAYER_SELECT:
6150 player_select_init();
6153 case GS_STATE_MULTI_START_GAME:
6154 multi_start_game_init();
6157 case GS_STATE_MULTI_HOST_OPTIONS:
6158 multi_host_options_init();
6161 case GS_STATE_END_OF_CAMPAIGN:
6162 mission_campaign_end_init();
6165 case GS_STATE_LOOP_BRIEF:
6172 // do stuff that may need to be done regardless of state
6173 void game_do_state_common(int state,int no_networking)
6175 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6176 snd_do_frame(); // update sound system
6177 event_music_do_frame(); // music needs to play across many states
6179 multi_log_process();
6181 if (no_networking) {
6185 // maybe do a multiplayer frame based on game mode and state type
6186 if (Game_mode & GM_MULTIPLAYER) {
6188 case GS_STATE_OPTIONS_MENU:
6189 case GS_STATE_GAMEPLAY_HELP:
6190 case GS_STATE_HOTKEY_SCREEN:
6191 case GS_STATE_HUD_CONFIG:
6192 case GS_STATE_CONTROL_CONFIG:
6193 case GS_STATE_MISSION_LOG_SCROLLBACK:
6194 case GS_STATE_SHOW_GOALS:
6195 case GS_STATE_VIEW_CUTSCENES:
6196 case GS_STATE_EVENT_DEBUG:
6197 multi_maybe_do_frame();
6201 game_do_networking();
6205 // Called once a frame.
6206 // You should never try to change the state
6207 // in here... if you think you need to, you probably really
6208 // need to post an event, not change the state.
6209 int Game_do_state_should_skip = 0;
6210 void game_do_state(int state)
6212 // always lets the do_state_common() function determine if the state should be skipped
6213 Game_do_state_should_skip = 0;
6215 // legal to set the should skip state anywhere in this function
6216 game_do_state_common(state); // do stuff that may need to be done regardless of state
6218 if(Game_do_state_should_skip){
6223 case GS_STATE_MAIN_MENU:
6224 game_set_frametime(GS_STATE_MAIN_MENU);
6225 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6228 main_hall_do(flFrametime);
6232 case GS_STATE_OPTIONS_MENU:
6233 game_set_frametime(GS_STATE_OPTIONS_MENU);
6234 options_menu_do_frame(flFrametime);
6237 case GS_STATE_BARRACKS_MENU:
6238 game_set_frametime(GS_STATE_BARRACKS_MENU);
6239 barracks_do_frame(flFrametime);
6242 case GS_STATE_TRAINING_MENU:
6243 game_set_frametime(GS_STATE_TRAINING_MENU);
6244 training_menu_do_frame(flFrametime);
6247 case GS_STATE_TECH_MENU:
6248 game_set_frametime(GS_STATE_TECH_MENU);
6249 techroom_do_frame(flFrametime);
6252 case GS_STATE_GAMEPLAY_HELP:
6253 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6254 gameplay_help_do_frame(flFrametime);
6257 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6261 case GS_STATE_GAME_PAUSED:
6265 case GS_STATE_DEBUG_PAUSED:
6267 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6272 case GS_STATE_TRAINING_PAUSED:
6273 game_training_pause_do();
6276 case GS_STATE_LOAD_MISSION_MENU:
6277 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6278 mission_load_menu_do();
6281 case GS_STATE_BRIEFING:
6282 game_set_frametime(GS_STATE_BRIEFING);
6283 brief_do_frame(flFrametime);
6286 case GS_STATE_DEBRIEF:
6287 game_set_frametime(GS_STATE_DEBRIEF);
6288 debrief_do_frame(flFrametime);
6291 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6292 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6293 multi_df_debrief_do();
6296 case GS_STATE_SHIP_SELECT:
6297 game_set_frametime(GS_STATE_SHIP_SELECT);
6298 ship_select_do(flFrametime);
6301 case GS_STATE_WEAPON_SELECT:
6302 game_set_frametime(GS_STATE_WEAPON_SELECT);
6303 weapon_select_do(flFrametime);
6306 case GS_STATE_MISSION_LOG_SCROLLBACK:
6307 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6308 hud_scrollback_do_frame(flFrametime);
6311 case GS_STATE_HUD_CONFIG:
6312 game_set_frametime(GS_STATE_HUD_CONFIG);
6313 hud_config_do_frame(flFrametime);
6316 case GS_STATE_MULTI_JOIN_GAME:
6317 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6318 multi_join_game_do_frame();
6321 case GS_STATE_MULTI_HOST_SETUP:
6322 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6323 multi_create_game_do();
6326 case GS_STATE_MULTI_CLIENT_SETUP:
6327 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6328 multi_game_client_setup_do_frame();
6331 case GS_STATE_CONTROL_CONFIG:
6332 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6333 control_config_do_frame(flFrametime);
6336 case GS_STATE_DEATH_DIED:
6340 case GS_STATE_DEATH_BLEW_UP:
6344 case GS_STATE_SIMULATOR_ROOM:
6345 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6346 sim_room_do_frame(flFrametime);
6349 case GS_STATE_CAMPAIGN_ROOM:
6350 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6351 campaign_room_do_frame(flFrametime);
6354 case GS_STATE_RED_ALERT:
6355 game_set_frametime(GS_STATE_RED_ALERT);
6356 red_alert_do_frame(flFrametime);
6359 case GS_STATE_CMD_BRIEF:
6360 game_set_frametime(GS_STATE_CMD_BRIEF);
6361 cmd_brief_do_frame(flFrametime);
6364 case GS_STATE_CREDITS:
6365 game_set_frametime(GS_STATE_CREDITS);
6366 credits_do_frame(flFrametime);
6369 case GS_STATE_VIEW_MEDALS:
6370 game_set_frametime(GS_STATE_VIEW_MEDALS);
6374 case GS_STATE_SHOW_GOALS:
6375 game_set_frametime(GS_STATE_SHOW_GOALS);
6376 mission_show_goals_do_frame(flFrametime);
6379 case GS_STATE_HOTKEY_SCREEN:
6380 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6381 mission_hotkey_do_frame(flFrametime);
6384 case GS_STATE_VIEW_CUTSCENES:
6385 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6386 cutscenes_screen_do_frame();
6389 case GS_STATE_MULTI_STD_WAIT:
6390 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6391 multi_standalone_wait_do();
6394 case GS_STATE_STANDALONE_MAIN:
6395 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6396 standalone_main_do();
6399 case GS_STATE_MULTI_PAUSED:
6400 game_set_frametime(GS_STATE_MULTI_PAUSED);
6404 case GS_STATE_TEAM_SELECT:
6405 game_set_frametime(GS_STATE_TEAM_SELECT);
6409 case GS_STATE_INGAME_PRE_JOIN:
6410 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6411 multi_ingame_select_do();
6414 case GS_STATE_EVENT_DEBUG:
6416 game_set_frametime(GS_STATE_EVENT_DEBUG);
6417 game_show_event_debug(flFrametime);
6421 case GS_STATE_STANDALONE_POSTGAME:
6422 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6423 multi_standalone_postgame_do();
6426 case GS_STATE_INITIAL_PLAYER_SELECT:
6427 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6431 case GS_STATE_MULTI_MISSION_SYNC:
6432 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6436 case GS_STATE_MULTI_START_GAME:
6437 game_set_frametime(GS_STATE_MULTI_START_GAME);
6438 multi_start_game_do();
6441 case GS_STATE_MULTI_HOST_OPTIONS:
6442 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6443 multi_host_options_do();
6446 case GS_STATE_END_OF_CAMPAIGN:
6447 mission_campaign_end_do();
6450 case GS_STATE_END_DEMO:
6451 game_set_frametime(GS_STATE_END_DEMO);
6452 end_demo_campaign_do();
6455 case GS_STATE_LOOP_BRIEF:
6456 game_set_frametime(GS_STATE_LOOP_BRIEF);
6460 } // end switch(gs_current_state)
6464 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6465 int game_do_ram_check(int ram_in_bytes)
6467 if ( ram_in_bytes < 30*1024*1024 ) {
6468 int allowed_to_run = 1;
6469 if ( ram_in_bytes < 25*1024*1024 ) {
6474 int Freespace_total_ram_MB;
6475 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6477 if ( allowed_to_run ) {
6479 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);
6483 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6484 if ( msgbox_rval == IDCANCEL ) {
6491 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);
6493 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6504 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6505 // If so, copy it over and remove the update directory.
6506 void game_maybe_update_launcher(char *exe_dir)
6509 char src_filename[MAX_PATH];
6510 char dest_filename[MAX_PATH];
6512 strcpy(src_filename, exe_dir);
6513 strcat(src_filename, NOX("\\update\\freespace.exe"));
6515 strcpy(dest_filename, exe_dir);
6516 strcat(dest_filename, NOX("\\freespace.exe"));
6518 // see if src_filename exists
6520 fp = fopen(src_filename, "rb");
6526 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6528 // copy updated freespace.exe to freespace exe dir
6529 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6530 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 );
6534 // delete the file in the update directory
6535 DeleteFile(src_filename);
6537 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6538 char update_dir[MAX_PATH];
6539 strcpy(update_dir, exe_dir);
6540 strcat(update_dir, NOX("\\update"));
6541 RemoveDirectory(update_dir);
6547 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6551 int sub_total_destroyed = 0;
6555 // get the total for all his children
6556 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6557 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6560 // find the # of faces for this _individual_ object
6561 total = submodel_get_num_polys(model_num, sm);
6562 if(strstr(pm->submodel[sm].name, "-destroyed")){
6563 sub_total_destroyed = total;
6567 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6570 *out_total += total + sub_total;
6571 *out_destroyed_total += sub_total_destroyed;
6574 #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);
6575 void game_spew_pof_info()
6577 char *pof_list[1000];
6580 int idx, model_num, i, j;
6582 int total, root_total, model_total, destroyed_total, counted;
6586 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6588 // spew info on all the pofs
6594 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6599 for(idx=0; idx<num_files; idx++, counted++){
6600 sprintf(str, "%s.pof", pof_list[idx]);
6601 model_num = model_load(str, 0, NULL);
6603 pm = model_get(model_num);
6605 // if we have a real model
6610 // go through and print all raw submodels
6611 cfputs("RAW\n", out);
6614 for (i=0; i<pm->n_models; i++) {
6615 total = submodel_get_num_polys(model_num, i);
6617 model_total += total;
6618 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6621 sprintf(str, "Model total %d\n", model_total);
6624 // now go through and do it by LOD
6625 cfputs("BY LOD\n\n", out);
6626 for(i=0; i<pm->n_detail_levels; i++){
6627 sprintf(str, "LOD %d\n", i);
6631 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6633 destroyed_total = 0;
6634 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6635 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6638 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6641 sprintf(str, "TOTAL: %d\n", total + root_total);
6643 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6645 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6648 cfputs("------------------------------------------------------------------------\n\n", out);
6652 if(counted >= MAX_POLYGON_MODELS - 5){
6665 game_spew_pof_info();
6668 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6673 // Don't let more than one instance of Freespace run.
6674 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6676 SetForegroundWindow(hwnd);
6681 // Find out how much RAM is on this machine
6684 ms.dwLength = sizeof(MEMORYSTATUS);
6685 GlobalMemoryStatus(&ms);
6686 Freespace_total_ram = ms.dwTotalPhys;
6688 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6692 if ( ms.dwTotalVirtual < 1024 ) {
6693 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6697 if (!vm_init(24*1024*1024)) {
6698 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 );
6702 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6704 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);
6714 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6715 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6716 seem worth bothering with.
6720 lResult = RegOpenKeyEx(
6721 HKEY_LOCAL_MACHINE, // Where it is
6722 "Software\\Microsoft\\DirectX", // name of key
6723 NULL, // DWORD reserved
6724 KEY_QUERY_VALUE, // Allows all changes
6725 &hKey // Location to store key
6728 if (lResult == ERROR_SUCCESS) {
6730 DWORD dwType, dwLen;
6733 lResult = RegQueryValueEx(
6734 hKey, // Handle to key
6735 "Version", // The values name
6736 NULL, // DWORD reserved
6737 &dwType, // What kind it is
6738 (ubyte *) version, // value to set
6739 &dwLen // How many bytes to set
6742 if (lResult == ERROR_SUCCESS) {
6743 dx_version = atoi(strstr(version, ".") + 1);
6747 DWORD dwType, dwLen;
6750 lResult = RegQueryValueEx(
6751 hKey, // Handle to key
6752 "InstalledVersion", // The values name
6753 NULL, // DWORD reserved
6754 &dwType, // What kind it is
6755 (ubyte *) &val, // value to set
6756 &dwLen // How many bytes to set
6759 if (lResult == ERROR_SUCCESS) {
6767 if (dx_version < 3) {
6768 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6769 "latest version of DirectX at:\n\n"
6770 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6772 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6773 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6778 //=====================================================
6779 // Make sure we're running in the right directory.
6783 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6784 char *p = exe_dir + strlen(exe_dir);
6786 // chop off the filename
6787 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6793 if ( strlen(exe_dir) > 0 ) {
6794 SetCurrentDirectory(exe_dir);
6797 // check for updated freespace.exe
6798 game_maybe_update_launcher(exe_dir);
6806 extern void windebug_memwatch_init();
6807 windebug_memwatch_init();
6811 parse_cmdline(szCmdLine);
6813 #ifdef STANDALONE_ONLY_BUILD
6815 nprintf(("Network", "Standalone running"));
6818 nprintf(("Network", "Standalone running"));
6826 // maybe spew pof stuff
6827 if(Cmdline_spew_pof_info){
6828 game_spew_pof_info();
6833 // non-demo, non-standalone, play the intro movie
6838 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) ){
6840 #if defined(OEM_BUILD)
6841 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6843 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6844 #endif // defined(OEM_BUILD)
6849 if ( !Is_standalone ) {
6851 // release -- movies always play
6854 // 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
6856 // movie_play( NOX("intro.mve"), 0 );
6858 // debug version, movie will only play with -showmovies
6859 #elif !defined(NDEBUG)
6862 // movie_play( NOX("intro.mve"), 0);
6865 if ( Cmdline_show_movies )
6866 movie_play( NOX("intro.mve"), 0 );
6875 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6877 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6881 // only important for non THREADED mode
6884 state = gameseq_process_events();
6885 if ( state == GS_STATE_QUIT_GAME ){
6892 demo_upsell_show_screens();
6894 #elif defined(OEM_BUILD)
6895 // show upsell screens on exit
6896 oem_upsell_show_screens();
6903 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6909 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6911 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6913 // Do nothing here - RecordExceptionInfo() has already done
6914 // everything that is needed. Actually this code won't even
6915 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6916 // the __except clause.
6922 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6923 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6929 // launcher the fslauncher program on exit
6930 void game_launch_launcher_on_exit()
6934 PROCESS_INFORMATION pi;
6935 char cmd_line[2048];
6936 char original_path[1024] = "";
6938 memset( &si, 0, sizeof(STARTUPINFO) );
6942 _getcwd(original_path, 1023);
6944 // set up command line
6945 strcpy(cmd_line, original_path);
6946 strcat(cmd_line, "\\");
6947 strcat(cmd_line, LAUNCHER_FNAME);
6948 strcat(cmd_line, " -straight_to_update");
6950 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6951 cmd_line, // pointer to command line string
6952 NULL, // pointer to process security attributes
6953 NULL, // pointer to thread security attributes
6954 FALSE, // handle inheritance flag
6955 CREATE_DEFAULT_ERROR_MODE, // creation flags
6956 NULL, // pointer to new environment block
6957 NULL, // pointer to current directory name
6958 &si, // pointer to STARTUPINFO
6959 &pi // pointer to PROCESS_INFORMATION
6961 // to eliminate build warnings
6971 // This function is called when FreeSpace terminates normally.
6973 void game_shutdown(void)
6979 // don't ever flip a page on the standalone!
6980 if(!(Game_mode & GM_STANDALONE_SERVER)){
6986 // if the player has left the "player select" screen and quit the game without actually choosing
6987 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6988 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6992 // load up common multiplayer icons
6993 multi_unload_common_icons();
6995 shockwave_close(); // release any memory used by shockwave system
6996 fireball_close(); // free fireball system
6997 ship_close(); // free any memory that was allocated for the ships
6998 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6999 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7000 bm_unload_all(); // free bitmaps
7001 mission_campaign_close(); // close out the campaign stuff
7002 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7004 #ifdef MULTI_USE_LAG
7008 // the menu close functions will unload the bitmaps if they were displayed during the game
7009 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7012 training_menu_close();
7015 extern void joy_close();
7018 audiostream_close();
7020 event_music_close();
7024 // HACKITY HACK HACK
7025 // if this flag is set, we should be firing up the launcher when exiting freespace
7026 extern int Multi_update_fireup_launcher_on_exit;
7027 if(Multi_update_fireup_launcher_on_exit){
7028 game_launch_launcher_on_exit();
7032 // game_stop_looped_sounds()
7034 // This function will call the appropriate stop looped sound functions for those
7035 // modules which use looping sounds. It is not enough just to stop a looping sound
7036 // at the DirectSound level, the game is keeping track of looping sounds, and this
7037 // function is used to inform the game that looping sounds are being halted.
7039 void game_stop_looped_sounds()
7041 hud_stop_looped_locking_sounds();
7042 hud_stop_looped_engine_sounds();
7043 afterburner_stop_sounds();
7044 player_stop_looped_sounds();
7045 obj_snd_stop_all(); // stop all object-linked persistant sounds
7046 game_stop_subspace_ambient_sound();
7047 snd_stop(Radar_static_looping);
7048 Radar_static_looping = -1;
7049 snd_stop(Target_static_looping);
7050 shipfx_stop_engine_wash_sound();
7051 Target_static_looping = -1;
7054 //////////////////////////////////////////////////////////////////////////
7056 // Code for supporting an animating mouse pointer
7059 //////////////////////////////////////////////////////////////////////////
7061 typedef struct animating_obj
7070 static animating_obj Animating_mouse;
7072 // ----------------------------------------------------------------------------
7073 // init_animating_pointer()
7075 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7076 // gets properly initialized
7078 void init_animating_pointer()
7080 Animating_mouse.first_frame = -1;
7081 Animating_mouse.num_frames = 0;
7082 Animating_mouse.current_frame = -1;
7083 Animating_mouse.time = 0.0f;
7084 Animating_mouse.elapsed_time = 0.0f;
7087 // ----------------------------------------------------------------------------
7088 // load_animating_pointer()
7090 // Called at game init to load in the frames for the animating mouse pointer
7092 // input: filename => filename of animation file that holds the animation
7094 void load_animating_pointer(char *filename, int dx, int dy)
7099 init_animating_pointer();
7101 am = &Animating_mouse;
7102 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7103 if ( am->first_frame == -1 )
7104 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7105 am->current_frame = 0;
7106 am->time = am->num_frames / i2fl(fps);
7109 // ----------------------------------------------------------------------------
7110 // unload_animating_pointer()
7112 // Called at game shutdown to free the memory used to store the animation frames
7114 void unload_animating_pointer()
7119 am = &Animating_mouse;
7120 for ( i = 0; i < am->num_frames; i++ ) {
7121 Assert( (am->first_frame+i) >= 0 );
7122 bm_release(am->first_frame + i);
7125 am->first_frame = -1;
7127 am->current_frame = -1;
7130 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7131 void game_render_mouse(float frametime)
7136 // if animating cursor exists, play the next frame
7137 am = &Animating_mouse;
7138 if ( am->first_frame != -1 ) {
7139 mouse_get_pos(&mx, &my);
7140 am->elapsed_time += frametime;
7141 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7142 if ( am->current_frame >= am->num_frames ) {
7143 am->current_frame = 0;
7144 am->elapsed_time = 0.0f;
7146 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7150 // ----------------------------------------------------------------------------
7151 // game_maybe_draw_mouse()
7153 // determines whether to draw the mouse pointer at all, and what frame of
7154 // animation to use if the mouse is animating
7156 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7158 // input: frametime => elapsed frame time in seconds since last call
7160 void game_maybe_draw_mouse(float frametime)
7164 game_state = gameseq_get_state();
7166 switch ( game_state ) {
7167 case GS_STATE_GAME_PAUSED:
7168 // case GS_STATE_MULTI_PAUSED:
7169 case GS_STATE_GAME_PLAY:
7170 case GS_STATE_DEATH_DIED:
7171 case GS_STATE_DEATH_BLEW_UP:
7172 if ( popup_active() || popupdead_is_active() ) {
7184 if ( !Mouse_hidden )
7185 game_render_mouse(frametime);
7189 void game_do_training_checks()
7193 waypoint_list *wplp;
7195 if (Training_context & TRAINING_CONTEXT_SPEED) {
7196 s = (int) Player_obj->phys_info.fspeed;
7197 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7198 if (!Training_context_speed_set) {
7199 Training_context_speed_set = 1;
7200 Training_context_speed_timestamp = timestamp();
7204 Training_context_speed_set = 0;
7207 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7208 wplp = &Waypoint_lists[Training_context_path];
7209 if (wplp->count > Training_context_goal_waypoint) {
7210 i = Training_context_goal_waypoint;
7212 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7213 if (d <= Training_context_distance) {
7214 Training_context_at_waypoint = i;
7215 if (Training_context_goal_waypoint == i) {
7216 Training_context_goal_waypoint++;
7217 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7224 if (i == wplp->count)
7227 } while (i != Training_context_goal_waypoint);
7231 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7232 Players_target = Player_ai->target_objnum;
7233 Players_targeted_subsys = Player_ai->targeted_subsys;
7234 Players_target_timestamp = timestamp();
7238 /////////// Following is for event debug view screen
7242 #define EVENT_DEBUG_MAX 5000
7243 #define EVENT_DEBUG_EVENT 0x8000
7245 int Event_debug_index[EVENT_DEBUG_MAX];
7248 void game_add_event_debug_index(int n, int indent)
7250 if (ED_count < EVENT_DEBUG_MAX)
7251 Event_debug_index[ED_count++] = n | (indent << 16);
7254 void game_add_event_debug_sexp(int n, int indent)
7259 if (Sexp_nodes[n].first >= 0) {
7260 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7261 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7265 game_add_event_debug_index(n, indent);
7266 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7267 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7269 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7272 void game_event_debug_init()
7277 for (e=0; e<Num_mission_events; e++) {
7278 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7279 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7283 void game_show_event_debug(float frametime)
7287 int font_height, font_width;
7289 static int scroll_offset = 0;
7291 k = game_check_key();
7297 if (scroll_offset < 0)
7307 scroll_offset -= 20;
7308 if (scroll_offset < 0)
7313 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7317 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7323 gr_set_color_fast(&Color_bright);
7325 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7327 gr_set_color_fast(&Color_normal);
7329 gr_get_string_size(&font_width, &font_height, NOX("test"));
7330 y_max = gr_screen.max_h - font_height - 5;
7334 while (k < ED_count) {
7335 if (y_index > y_max)
7338 z = Event_debug_index[k];
7339 if (z & EVENT_DEBUG_EVENT) {
7341 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7342 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7343 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7344 Mission_events[z].repeat_count, Mission_events[z].interval);
7352 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7353 switch (Sexp_nodes[z & 0x7fff].value) {
7355 strcat(buf, NOX(" (True)"));
7359 strcat(buf, NOX(" (False)"));
7362 case SEXP_KNOWN_TRUE:
7363 strcat(buf, NOX(" (Always true)"));
7366 case SEXP_KNOWN_FALSE:
7367 strcat(buf, NOX(" (Always false)"));
7370 case SEXP_CANT_EVAL:
7371 strcat(buf, NOX(" (Can't eval)"));
7375 case SEXP_NAN_FOREVER:
7376 strcat(buf, NOX(" (Not a number)"));
7381 gr_printf(10, y_index, buf);
7382 y_index += font_height;
7395 extern int Tmap_npixels;
7397 int Tmap_num_too_big = 0;
7398 int Num_models_needing_splitting = 0;
7400 void Time_model( int modelnum )
7402 // mprintf(( "Timing ship '%s'\n", si->name ));
7404 vector eye_pos, model_pos;
7405 matrix eye_orient, model_orient;
7407 polymodel *pm = model_get( modelnum );
7409 int l = strlen(pm->filename);
7411 if ( (l == '/') || (l=='\\') || (l==':')) {
7417 char *pof_file = &pm->filename[l];
7419 int model_needs_splitting = 0;
7421 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7423 for (i=0; i<pm->n_textures; i++ ) {
7424 char filename[1024];
7427 int bmp_num = pm->original_textures[i];
7428 if ( bmp_num > -1 ) {
7429 bm_get_palette(pm->original_textures[i], pal, filename );
7431 bm_get_info( pm->original_textures[i],&w, &h );
7434 if ( (w > 512) || (h > 512) ) {
7435 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7437 model_needs_splitting++;
7440 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7444 if ( model_needs_splitting ) {
7445 Num_models_needing_splitting++;
7447 eye_orient = model_orient = vmd_identity_matrix;
7448 eye_pos = model_pos = vmd_zero_vector;
7450 eye_pos.z = -pm->rad*2.0f;
7452 vector eye_to_model;
7454 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7455 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7457 fix t1 = timer_get_fixed_seconds();
7460 ta.p = ta.b = ta.h = 0.0f;
7465 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7467 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7469 modelstats_num_polys = modelstats_num_verts = 0;
7471 while( ta.h < PI2 ) {
7474 vm_angles_2_matrix(&m1, &ta );
7475 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7482 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7484 model_clear_instance( modelnum );
7485 model_set_detail_level(0); // use highest detail level
7486 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7494 int k = key_inkey();
7495 if ( k == KEY_ESC ) {
7500 fix t2 = timer_get_fixed_seconds();
7502 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7503 //bitmaps_used_this_frame /= framecount;
7505 modelstats_num_polys /= framecount;
7506 modelstats_num_verts /= framecount;
7508 Tmap_npixels /=framecount;
7511 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7512 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 );
7513 // 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 );
7519 int Time_models = 0;
7520 DCF_BOOL( time_models, Time_models );
7522 void Do_model_timings_test()
7526 if ( !Time_models ) return;
7528 mprintf(( "Timing models!\n" ));
7532 ubyte model_used[MAX_POLYGON_MODELS];
7533 int model_id[MAX_POLYGON_MODELS];
7534 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7539 for (i=0; i<Num_ship_types; i++ ) {
7540 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7542 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7543 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7546 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7547 if ( !Texture_fp ) return;
7549 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7550 if ( !Time_fp ) return;
7552 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7553 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7555 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7556 if ( model_used[i] ) {
7557 Time_model( model_id[i] );
7561 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7562 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7571 // Call this function when you want to inform the player that a feature is not
7572 // enabled in the DEMO version of FreSpace
7573 void game_feature_not_in_demo_popup()
7575 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7578 // format the specified time (fixed point) into a nice string
7579 void game_format_time(fix m_time,char *time_str)
7582 int hours,minutes,seconds;
7585 mtime = f2fl(m_time);
7587 // get the hours, minutes and seconds
7588 hours = (int)(mtime / 3600.0f);
7590 mtime -= (3600.0f * (float)hours);
7592 seconds = (int)mtime%60;
7593 minutes = (int)mtime/60;
7595 // print the hour if necessary
7597 sprintf(time_str,XSTR( "%d:", 201),hours);
7598 // if there are less than 10 minutes, print a leading 0
7600 strcpy(tmp,NOX("0"));
7601 strcat(time_str,tmp);
7605 // print the minutes
7607 sprintf(tmp,XSTR( "%d:", 201),minutes);
7608 strcat(time_str,tmp);
7610 sprintf(time_str,XSTR( "%d:", 201),minutes);
7613 // print the seconds
7615 strcpy(tmp,NOX("0"));
7616 strcat(time_str,tmp);
7618 sprintf(tmp,"%d",seconds);
7619 strcat(time_str,tmp);
7622 // Stuff version string in *str.
7623 void get_version_string(char *str)
7626 if ( FS_VERSION_BUILD == 0 ) {
7627 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7629 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7632 #if defined (FS2_DEMO)
7634 #elif defined (OEM_BUILD)
7635 strcat(str, " (OEM)");
7641 char myname[_MAX_PATH];
7642 int namelen, major, minor, build, waste;
7643 unsigned int buf_size;
7649 // Find my EXE file name
7650 hMod = GetModuleHandle(NULL);
7651 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7653 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7654 infop = (char *)malloc(version_size);
7655 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7657 // get the product version
7658 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7659 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7661 sprintf(str,"Dv%d.%02d",major, minor);
7663 sprintf(str,"v%d.%02d",major, minor);
7668 void get_version_string_short(char *str)
7670 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7673 // ----------------------------------------------------------------
7675 // OEM UPSELL SCREENS BEGIN
7677 // ----------------------------------------------------------------
7678 #if defined(OEM_BUILD)
7680 #define NUM_OEM_UPSELL_SCREENS 3
7681 #define OEM_UPSELL_SCREEN_DELAY 10000
7683 static int Oem_upsell_bitmaps_loaded = 0;
7684 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7685 static int Oem_upsell_screen_number = 0;
7686 static int Oem_upsell_show_next_bitmap_time;
7689 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7702 static int Oem_normal_cursor = -1;
7703 static int Oem_web_cursor = -1;
7704 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7705 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7707 void oem_upsell_next_screen()
7709 Oem_upsell_screen_number++;
7710 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7711 // extra long delay, mouse shown on last upsell
7712 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7716 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7720 void oem_upsell_load_bitmaps()
7724 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7725 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7729 void oem_upsell_unload_bitmaps()
7733 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7734 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7735 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7740 Oem_upsell_bitmaps_loaded = 0;
7743 // clickable hotspot on 3rd OEM upsell screen
7744 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7746 28, 350, 287, 96 // x, y, w, h
7749 45, 561, 460, 152 // x, y, w, h
7753 void oem_upsell_show_screens()
7755 int current_time, k;
7758 if ( !Oem_upsell_bitmaps_loaded ) {
7759 oem_upsell_load_bitmaps();
7760 Oem_upsell_bitmaps_loaded = 1;
7763 // may use upsell screens more than once
7764 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7765 Oem_upsell_screen_number = 0;
7771 int nframes; // used to pass, not really needed (should be 1)
7772 Oem_normal_cursor = gr_get_cursor_bitmap();
7773 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7774 Assert(Oem_web_cursor >= 0);
7775 if (Oem_web_cursor < 0) {
7776 Oem_web_cursor = Oem_normal_cursor;
7781 //oem_reset_trailer_timer();
7783 current_time = timer_get_milliseconds();
7788 // advance screen on keypress or timeout
7789 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7790 oem_upsell_next_screen();
7793 // check if we are done
7794 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7795 Oem_upsell_screen_number--;
7798 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7803 // show me the upsell
7804 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7805 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7809 // if this is the 3rd upsell, make it clickable, d00d
7810 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7812 int button_state = mouse_get_pos(&mx, &my);
7813 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])
7814 && (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]) )
7817 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7820 if (button_state & MOUSE_LEFT_BUTTON) {
7822 multi_pxo_url(OEM_UPSELL_URL);
7826 // switch cursor back to normal one
7827 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7832 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7842 oem_upsell_unload_bitmaps();
7844 // switch cursor back to normal one
7845 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7849 #endif // defined(OEM_BUILD)
7850 // ----------------------------------------------------------------
7852 // OEM UPSELL SCREENS END
7854 // ----------------------------------------------------------------
7858 // ----------------------------------------------------------------
7860 // DEMO UPSELL SCREENS BEGIN
7862 // ----------------------------------------------------------------
7866 //#define NUM_DEMO_UPSELL_SCREENS 4
7868 #define NUM_DEMO_UPSELL_SCREENS 2
7869 #define DEMO_UPSELL_SCREEN_DELAY 3000
7871 static int Demo_upsell_bitmaps_loaded = 0;
7872 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7873 static int Demo_upsell_screen_number = 0;
7874 static int Demo_upsell_show_next_bitmap_time;
7877 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7890 void demo_upsell_next_screen()
7892 Demo_upsell_screen_number++;
7893 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7894 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7896 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7900 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7901 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7902 #ifndef HARDWARE_ONLY
7903 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7910 void demo_upsell_load_bitmaps()
7914 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7915 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7919 void demo_upsell_unload_bitmaps()
7923 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7924 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7925 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7930 Demo_upsell_bitmaps_loaded = 0;
7933 void demo_upsell_show_screens()
7935 int current_time, k;
7938 if ( !Demo_upsell_bitmaps_loaded ) {
7939 demo_upsell_load_bitmaps();
7940 Demo_upsell_bitmaps_loaded = 1;
7943 // may use upsell screens more than once
7944 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7945 Demo_upsell_screen_number = 0;
7952 demo_reset_trailer_timer();
7954 current_time = timer_get_milliseconds();
7961 // don't time out, wait for keypress
7963 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7964 demo_upsell_next_screen();
7969 demo_upsell_next_screen();
7972 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7973 Demo_upsell_screen_number--;
7976 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7981 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7982 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7987 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7997 demo_upsell_unload_bitmaps();
8002 // ----------------------------------------------------------------
8004 // DEMO UPSELL SCREENS END
8006 // ----------------------------------------------------------------
8009 // ----------------------------------------------------------------
8011 // Subspace Ambient Sound START
8013 // ----------------------------------------------------------------
8015 static int Subspace_ambient_left_channel = -1;
8016 static int Subspace_ambient_right_channel = -1;
8019 void game_start_subspace_ambient_sound()
8021 if ( Subspace_ambient_left_channel < 0 ) {
8022 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8025 if ( Subspace_ambient_right_channel < 0 ) {
8026 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8030 void game_stop_subspace_ambient_sound()
8032 if ( Subspace_ambient_left_channel >= 0 ) {
8033 snd_stop(Subspace_ambient_left_channel);
8034 Subspace_ambient_left_channel = -1;
8037 if ( Subspace_ambient_right_channel >= 0 ) {
8038 snd_stop(Subspace_ambient_right_channel);
8039 Subspace_ambient_right_channel = -1;
8043 // ----------------------------------------------------------------
8045 // Subspace Ambient Sound END
8047 // ----------------------------------------------------------------
8049 // ----------------------------------------------------------------
8051 // CDROM detection code START
8053 // ----------------------------------------------------------------
8055 #define CD_SIZE_72_MINUTE_MAX (697000000)
8057 uint game_get_cd_used_space(char *path)
8061 char use_path[512] = "";
8062 char sub_path[512] = "";
8063 WIN32_FIND_DATA find;
8066 // recurse through all files and directories
8067 strcpy(use_path, path);
8068 strcat(use_path, "*.*");
8069 find_handle = FindFirstFile(use_path, &find);
8072 if(find_handle == INVALID_HANDLE_VALUE){
8078 // subdirectory. make sure to ignore . and ..
8079 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8081 strcpy(sub_path, path);
8082 strcat(sub_path, find.cFileName);
8083 strcat(sub_path, "\\");
8084 total += game_get_cd_used_space(sub_path);
8086 total += (uint)find.nFileSizeLow;
8088 } while(FindNextFile(find_handle, &find));
8091 FindClose(find_handle);
8103 // if volume_name is non-null, the CD name must match that
8104 int find_freespace_cd(char *volume_name)
8107 char oldpath[MAX_PATH];
8111 int volume_match = 0;
8115 GetCurrentDirectory(MAX_PATH, oldpath);
8117 for (i = 0; i < 26; i++)
8123 path[0] = (char)('A'+i);
8124 if (GetDriveType(path) == DRIVE_CDROM) {
8126 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8127 nprintf(("CD", "CD volume: %s\n", volume));
8129 // check for any CD volume
8130 int volume1_present = 0;
8131 int volume2_present = 0;
8132 int volume3_present = 0;
8134 char full_check[512] = "";
8136 // look for setup.exe
8137 strcpy(full_check, path);
8138 strcat(full_check, "setup.exe");
8139 find_handle = _findfirst(full_check, &find);
8140 if(find_handle != -1){
8141 volume1_present = 1;
8142 _findclose(find_handle);
8145 // look for intro.mve
8146 strcpy(full_check, path);
8147 strcat(full_check, "intro.mve");
8148 find_handle = _findfirst(full_check, &find);
8149 if(find_handle != -1){
8150 volume2_present = 1;
8151 _findclose(find_handle);
8154 // look for endpart1.mve
8155 strcpy(full_check, path);
8156 strcat(full_check, "endpart1.mve");
8157 find_handle = _findfirst(full_check, &find);
8158 if(find_handle != -1){
8159 volume3_present = 1;
8160 _findclose(find_handle);
8163 // see if we have the specific CD we're looking for
8164 if ( volume_name ) {
8166 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8170 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8174 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8178 if ( volume1_present || volume2_present || volume3_present ) {
8183 // 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
8184 if ( volume_match ){
8186 // 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
8187 if(volume2_present || volume3_present) {
8188 // first step - check to make sure its a cdrom
8189 if(GetDriveType(path) != DRIVE_CDROM){
8193 #if !defined(OEM_BUILD)
8194 // oem not on 80 min cds, so dont check tha size
8196 uint used_space = game_get_cd_used_space(path);
8197 if(used_space < CD_SIZE_72_MINUTE_MAX){
8200 #endif // !defined(OEM_BUILD)
8208 #endif // RELEASE_REAL
8214 SetCurrentDirectory(oldpath);
8223 int set_cdrom_path(int drive_num)
8227 if (drive_num < 0) { //no CD
8229 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8232 strcpy(Game_CDROM_dir,""); //set directory
8236 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8252 i = find_freespace_cd();
8254 rval = set_cdrom_path(i);
8258 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8260 nprintf(("CD", "FreeSpace CD not found\n"));
8268 int Last_cd_label_found = 0;
8269 char Last_cd_label[256];
8271 int game_cd_changed()
8278 if ( strlen(Game_CDROM_dir) == 0 ) {
8282 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8284 if ( found != Last_cd_label_found ) {
8285 Last_cd_label_found = found;
8287 mprintf(( "CD '%s' was inserted\n", label ));
8290 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8294 if ( Last_cd_label_found ) {
8295 if ( !stricmp( Last_cd_label, label )) {
8296 //mprintf(( "CD didn't change\n" ));
8298 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8302 // none found before, none found now.
8303 //mprintf(( "still no CD...\n" ));
8307 Last_cd_label_found = found;
8309 strcpy( Last_cd_label, label );
8311 strcpy( Last_cd_label, "" );
8322 // check if _any_ FreeSpace2 CDs are in the drive
8323 // return: 1 => CD now in drive
8324 // 0 => Could not find CD, they refuse to put it in the drive
8325 int game_do_cd_check(char *volume_name)
8327 #if !defined(GAME_CD_CHECK)
8333 int num_attempts = 0;
8334 int refresh_files = 0;
8336 int path_set_ok, popup_rval;
8338 cd_drive_num = find_freespace_cd(volume_name);
8339 path_set_ok = set_cdrom_path(cd_drive_num);
8340 if ( path_set_ok ) {
8342 if ( refresh_files ) {
8354 // no CD found, so prompt user
8355 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8357 if ( popup_rval != 1 ) {
8362 if ( num_attempts++ > 5 ) {
8373 // check if _any_ FreeSpace2 CDs are in the drive
8374 // return: 1 => CD now in drive
8375 // 0 => Could not find CD, they refuse to put it in the drive
8376 int game_do_cd_check_specific(char *volume_name, int cdnum)
8381 int num_attempts = 0;
8382 int refresh_files = 0;
8384 int path_set_ok, popup_rval;
8386 cd_drive_num = find_freespace_cd(volume_name);
8387 path_set_ok = set_cdrom_path(cd_drive_num);
8388 if ( path_set_ok ) {
8390 if ( refresh_files ) {
8401 // no CD found, so prompt user
8402 #if defined(DVD_MESSAGE_HACK)
8403 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8405 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8408 if ( popup_rval != 1 ) {
8413 if ( num_attempts++ > 5 ) {
8423 // only need to do this in RELEASE_REAL
8424 int game_do_cd_mission_check(char *filename)
8430 fs_builtin_mission *m = game_find_builtin_mission(filename);
8432 // check for changed CD
8433 if(game_cd_changed()){
8438 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8442 // not builtin, so do a general check (any FS2 CD will do)
8444 return game_do_cd_check();
8447 // does not have any CD requirement, do a general check
8448 if(strlen(m->cd_volume) <= 0){
8449 return game_do_cd_check();
8453 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8455 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8457 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8460 return game_do_cd_check();
8463 // did we find the cd?
8464 if(find_freespace_cd(m->cd_volume) >= 0){
8468 // make sure the volume exists
8469 int num_attempts = 0;
8470 int refresh_files = 0;
8472 int path_set_ok, popup_rval;
8474 cd_drive_num = find_freespace_cd(m->cd_volume);
8475 path_set_ok = set_cdrom_path(cd_drive_num);
8476 if ( path_set_ok ) {
8478 if ( refresh_files ) {
8485 // no CD found, so prompt user
8486 #if defined(DVD_MESSAGE_HACK)
8487 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8489 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8493 if ( popup_rval != 1 ) {
8498 if ( num_attempts++ > 5 ) {
8510 // ----------------------------------------------------------------
8512 // CDROM detection code END
8514 // ----------------------------------------------------------------
8516 // ----------------------------------------------------------------
8517 // SHIPS TBL VERIFICATION STUFF
8520 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8521 #define NUM_SHIPS_TBL_CHECKSUMS 1
8523 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8524 -463907578, // US - beta 1
8525 1696074201, // FS2 demo
8528 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8529 // -1022810006, // 1.0 FULL
8530 -1254285366 // 1.2 FULL (German)
8533 void verify_ships_tbl()
8537 Game_ships_tbl_valid = 1;
8543 // detect if the packfile exists
8544 CFILE *detect = cfopen("ships.tbl", "rb");
8545 Game_ships_tbl_valid = 0;
8549 Game_ships_tbl_valid = 0;
8553 // get the long checksum of the file
8555 cfseek(detect, 0, SEEK_SET);
8556 cf_chksum_long(detect, &file_checksum);
8560 // now compare the checksum/filesize against known #'s
8561 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8562 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8563 Game_ships_tbl_valid = 1;
8570 DCF(shipspew, "display the checksum for the current ships.tbl")
8573 CFILE *detect = cfopen("ships.tbl", "rb");
8574 // get the long checksum of the file
8576 cfseek(detect, 0, SEEK_SET);
8577 cf_chksum_long(detect, &file_checksum);
8580 dc_printf("%d", file_checksum);
8583 // ----------------------------------------------------------------
8584 // WEAPONS TBL VERIFICATION STUFF
8587 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8588 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8590 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8591 141718090, // US - beta 1
8592 -266420030, // demo 1
8595 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8596 // 399297860, // 1.0 FULL
8597 -553984927 // 1.2 FULL (german)
8600 void verify_weapons_tbl()
8604 Game_weapons_tbl_valid = 1;
8610 // detect if the packfile exists
8611 CFILE *detect = cfopen("weapons.tbl", "rb");
8612 Game_weapons_tbl_valid = 0;
8616 Game_weapons_tbl_valid = 0;
8620 // get the long checksum of the file
8622 cfseek(detect, 0, SEEK_SET);
8623 cf_chksum_long(detect, &file_checksum);
8627 // now compare the checksum/filesize against known #'s
8628 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8629 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8630 Game_weapons_tbl_valid = 1;
8637 DCF(wepspew, "display the checksum for the current weapons.tbl")
8640 CFILE *detect = cfopen("weapons.tbl", "rb");
8641 // get the long checksum of the file
8643 cfseek(detect, 0, SEEK_SET);
8644 cf_chksum_long(detect, &file_checksum);
8647 dc_printf("%d", file_checksum);
8650 // if the game is running using hacked data
8651 int game_hacked_data()
8654 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8662 void display_title_screen()
8664 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8665 ///int title_bitmap;
8668 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8669 if (title_bitmap == -1) {
8674 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8675 extern void d3d_start_frame();
8680 gr_set_bitmap(title_bitmap);
8686 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8687 extern void d3d_stop_frame();
8694 bm_unload(title_bitmap);
8695 #endif // FS2_DEMO || OEM_BUILD
8698 // return true if the game is running with "low memory", which is less than 48MB
8699 bool game_using_low_mem()
8701 if (Use_low_mem == 0) {