2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.15 2002/06/05 08:05:28 relnev
11 * stub/warning removal.
13 * reworked the sound code.
15 * Revision 1.14 2002/06/05 04:03:32 relnev
16 * finished cfilesystem.
18 * removed some old code.
20 * fixed mouse save off-by-one.
24 * Revision 1.13 2002/06/02 04:26:34 relnev
27 * Revision 1.12 2002/06/02 00:31:35 relnev
28 * implemented osregistry
30 * Revision 1.11 2002/06/01 09:00:34 relnev
31 * silly debug memmanager
33 * Revision 1.10 2002/06/01 07:12:32 relnev
34 * a few NDEBUG updates.
36 * removed a few warnings.
38 * Revision 1.9 2002/05/31 03:05:59 relnev
41 * Revision 1.8 2002/05/29 02:52:32 theoddone33
42 * Enable OpenGL renderer
44 * Revision 1.7 2002/05/28 08:52:03 relnev
45 * implemented two assembly stubs.
47 * cleaned up a few warnings.
49 * added a little demo hackery to make it progress a little farther.
51 * Revision 1.6 2002/05/28 06:28:20 theoddone33
52 * Filesystem mods, actually reads some data files now
54 * Revision 1.5 2002/05/28 04:07:28 theoddone33
55 * New graphics stubbing arrangement
57 * Revision 1.4 2002/05/27 22:46:52 theoddone33
58 * Remove more undefined symbols
60 * Revision 1.3 2002/05/26 23:31:18 relnev
61 * added a few files that needed to be compiled
63 * freespace.cpp: now compiles
65 * Revision 1.2 2002/05/07 03:16:44 theoddone33
66 * The Great Newline Fix
68 * Revision 1.1.1.1 2002/05/03 03:28:09 root
72 * 201 6/16/00 3:15p Jefff
73 * sim of the year dvd version changes, a few german soty localization
76 * 200 11/03/99 11:06a Jefff
79 * 199 10/26/99 5:07p Jamest
80 * fixed jeffs dumb debug code
82 * 198 10/25/99 5:53p Jefff
83 * call control_config_common_init() on startup
85 * 197 10/14/99 10:18a Daveb
86 * Fixed incorrect CD checking problem on standalone server.
88 * 196 10/13/99 9:22a Daveb
89 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
90 * related to movies. Fixed launcher spawning from PXO screen.
92 * 195 10/06/99 11:05a Jefff
93 * new oem upsell 3 hotspot coords
95 * 194 10/06/99 10:31a Jefff
98 * 193 10/01/99 9:10a Daveb
101 * 192 9/15/99 4:57a Dave
102 * Updated ships.tbl checksum
104 * 191 9/15/99 3:58a Dave
105 * Removed framerate warning at all times.
107 * 190 9/15/99 3:16a Dave
108 * Remove mt-011.fs2 from the builtin mission list.
110 * 189 9/15/99 1:45a Dave
111 * Don't init joystick on standalone. Fixed campaign mode on standalone.
112 * Fixed no-score-report problem in TvT
114 * 188 9/14/99 6:08a Dave
115 * Updated (final) single, multi, and campaign list.
117 * 187 9/14/99 3:26a Dave
118 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
119 * respawn-too-early problem. Made a few crash points safe.
121 * 186 9/13/99 4:52p Dave
124 * 185 9/12/99 8:09p Dave
125 * Fixed problem where skip-training button would cause mission messages
126 * not to get paged out for the current mission.
128 * 184 9/10/99 11:53a Dave
129 * Shutdown graphics before sound to eliminate apparent lockups when
130 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
132 * 183 9/09/99 11:40p Dave
133 * Handle an Assert() in beam code. Added supernova sounds. Play the right
134 * 2 end movies properly, based upon what the player did in the mission.
136 * 182 9/08/99 10:29p Dave
137 * Make beam sound pausing and unpausing much safer.
139 * 181 9/08/99 10:01p Dave
140 * Make sure game won't run in a drive's root directory. Make sure
141 * standalone routes suqad war messages properly to the host.
143 * 180 9/08/99 3:22p Dave
144 * Updated builtin mission list.
146 * 179 9/08/99 12:01p Jefff
147 * fixed Game_builtin_mission_list typo on Training-2.fs2
149 * 178 9/08/99 9:48a Andsager
150 * Add force feedback for engine wash.
152 * 177 9/07/99 4:01p Dave
153 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
154 * does everything properly (setting up address when binding). Remove
155 * black rectangle background from UI_INPUTBOX.
157 * 176 9/13/99 2:40a Dave
158 * Comment in full 80 minute CD check for RELEASE_REAL builds.
160 * 175 9/06/99 6:38p Dave
161 * Improved CD detection code.
163 * 174 9/06/99 1:30a Dave
164 * Intermediate checkin. Started on enforcing CD-in-drive to play the
167 * 173 9/06/99 1:16a Dave
168 * Make sure the user sees the intro movie.
170 * 172 9/04/99 8:00p Dave
171 * Fixed up 1024 and 32 bit movie support.
173 * 171 9/03/99 1:32a Dave
174 * CD checking by act. Added support to play 2 cutscenes in a row
175 * seamlessly. Fixed super low level cfile bug related to files in the
176 * root directory of a CD. Added cheat code to set campaign mission # in
179 * 170 9/01/99 10:49p Dave
180 * Added nice SquadWar checkbox to the client join wait screen.
182 * 169 9/01/99 10:14a Dave
185 * 168 8/29/99 4:51p Dave
186 * Fixed damaged checkin.
188 * 167 8/29/99 4:18p Andsager
189 * New "burst" limit for friendly damage. Also credit more damage done
190 * against large friendly ships.
192 * 166 8/27/99 6:38p Alanl
193 * crush the blasted repeating messages bug
195 * 164 8/26/99 9:09p Dave
196 * Force framerate check in everything but a RELEASE_REAL build.
198 * 163 8/26/99 9:45a Dave
199 * First pass at easter eggs and cheats.
201 * 162 8/24/99 8:55p Dave
202 * Make sure nondimming pixels work properly in tech menu.
204 * 161 8/24/99 1:49a Dave
205 * Fixed client-side afterburner stuttering. Added checkbox for no version
206 * checking on PXO join. Made button info passing more friendly between
209 * 160 8/22/99 5:53p Dave
210 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
211 * instead of ship designations for multiplayer players.
213 * 159 8/22/99 1:19p Dave
214 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
215 * which d3d cards are detected.
217 * 158 8/20/99 2:09p Dave
218 * PXO banner cycling.
220 * 157 8/19/99 10:59a Dave
221 * Packet loss detection.
223 * 156 8/19/99 10:12a Alanl
224 * preload mission-specific messages on machines greater than 48MB
226 * 155 8/16/99 4:04p Dave
227 * Big honking checkin.
229 * 154 8/11/99 5:54p Dave
230 * Fixed collision problem. Fixed standalone ghost problem.
232 * 153 8/10/99 7:59p Jefff
235 * 152 8/10/99 6:54p Dave
236 * Mad optimizations. Added paging to the nebula effect.
238 * 151 8/10/99 3:44p Jefff
239 * loads Intelligence information on startup
241 * 150 8/09/99 3:47p Dave
242 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
243 * non-nebula missions.
245 * 149 8/09/99 2:21p Andsager
246 * Fix patching from multiplayer direct to launcher update tab.
248 * 148 8/09/99 10:36a Dave
249 * Version info for game.
251 * 147 8/06/99 9:46p Dave
252 * Hopefully final changes for the demo.
254 * 146 8/06/99 3:34p Andsager
255 * Make title version info "(D)" -> "D" show up nicely
257 * 145 8/06/99 2:59p Adamp
258 * Fixed NT launcher/update problem.
260 * 144 8/06/99 1:52p Dave
261 * Bumped up MAX_BITMAPS for the demo.
263 * 143 8/06/99 12:17p Andsager
264 * Demo: down to just 1 demo dog
266 * 142 8/05/99 9:39p Dave
267 * Yet another new checksum.
269 * 141 8/05/99 6:19p Dave
270 * New demo checksums.
272 * 140 8/05/99 5:31p Andsager
273 * Up demo version 1.01
275 * 139 8/05/99 4:22p Andsager
276 * No time limit on upsell screens. Reverse order of display of upsell
279 * 138 8/05/99 4:17p Dave
280 * Tweaks to client interpolation.
282 * 137 8/05/99 3:52p Danw
284 * 136 8/05/99 3:01p Danw
286 * 135 8/05/99 2:43a Anoop
287 * removed duplicate definition.
289 * 134 8/05/99 2:13a Dave
292 * 133 8/05/99 2:05a Dave
295 * 132 8/05/99 1:22a Andsager
298 * 131 8/04/99 9:51p Andsager
299 * Add title screen to demo
301 * 130 8/04/99 6:47p Jefff
302 * fixed link error resulting from #ifdefs
304 * 129 8/04/99 6:26p Dave
305 * Updated ship tbl checksum.
307 * 128 8/04/99 5:40p Andsager
308 * Add multiple demo dogs
310 * 127 8/04/99 5:36p Andsager
311 * Show upsell screens at end of demo campaign before returning to main
314 * 126 8/04/99 11:42a Danw
315 * tone down EAX reverb
317 * 125 8/04/99 11:23a Dave
318 * Updated demo checksums.
320 * 124 8/03/99 11:02p Dave
321 * Maybe fixed sync problems in multiplayer.
323 * 123 8/03/99 6:21p Jefff
326 * 122 8/03/99 3:44p Andsager
327 * Launch laucher if trying to run FS without first having configured
330 * 121 8/03/99 12:45p Dave
333 * 120 8/02/99 9:13p Dave
336 * 119 7/30/99 10:31p Dave
337 * Added comm menu to the configurable hud files.
339 * 118 7/30/99 5:17p Andsager
340 * first fs2demo checksums
342 * 117 7/29/99 3:09p Anoop
344 * 116 7/29/99 12:05a Dave
345 * Nebula speed optimizations.
347 * 115 7/27/99 8:59a Andsager
348 * Make major, minor version consistent for all builds. Only show major
349 * and minor for launcher update window.
351 * 114 7/26/99 5:50p Dave
352 * Revised ingame join. Better? We'll see....
354 * 113 7/26/99 5:27p Andsager
355 * Add training mission as builtin to demo build
357 * 112 7/24/99 1:54p Dave
358 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
361 * 111 7/22/99 4:00p Dave
362 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
364 * 110 7/21/99 8:10p Dave
365 * First run of supernova effect.
367 * 109 7/20/99 1:49p Dave
368 * Peter Drake build. Fixed some release build warnings.
370 * 108 7/19/99 2:26p Andsager
371 * set demo multiplayer missions
373 * 107 7/18/99 5:19p Dave
374 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
376 * 106 7/16/99 1:50p Dave
377 * 8 bit aabitmaps. yay.
379 * 105 7/15/99 3:07p Dave
380 * 32 bit detection support. Mouse coord commandline.
382 * 104 7/15/99 2:13p Dave
383 * Added 32 bit detection.
385 * 103 7/15/99 9:20a Andsager
386 * FS2_DEMO initial checkin
388 * 102 7/14/99 11:02a Dave
389 * Skill level default back to easy. Blech.
391 * 101 7/09/99 5:54p Dave
392 * Seperated cruiser types into individual types. Added tons of new
393 * briefing icons. Campaign screen.
395 * 100 7/08/99 4:43p Andsager
396 * New check for sparky_hi and print if not found.
398 * 99 7/08/99 10:53a Dave
399 * New multiplayer interpolation scheme. Not 100% done yet, but still
400 * better than the old way.
402 * 98 7/06/99 4:24p Dave
403 * Mid-level checkin. Starting on some potentially cool multiplayer
406 * 97 7/06/99 3:35p Andsager
407 * Allow movie to play before red alert mission.
409 * 96 7/03/99 5:50p Dave
410 * Make rotated bitmaps draw properly in padlock views.
412 * 95 7/02/99 9:55p Dave
413 * Player engine wash sound.
415 * 94 7/02/99 4:30p Dave
416 * Much more sophisticated lightning support.
418 * 93 6/29/99 7:52p Dave
419 * Put in exception handling in FS2.
421 * 92 6/22/99 9:37p Dave
422 * Put in pof spewing.
424 * 91 6/16/99 4:06p Dave
425 * New pilot info popup. Added new draw-bitmap-as-poly function.
427 * 90 6/15/99 1:56p Andsager
428 * For release builds, allow start up in high res only with
431 * 89 6/15/99 9:34a Dave
432 * Fixed key checking in single threaded version of the stamp notification
435 * 88 6/09/99 2:55p Andsager
436 * Allow multiple asteroid subtypes (of large, medium, small) and follow
439 * 87 6/08/99 1:14a Dave
440 * Multi colored hud test.
442 * 86 6/04/99 9:52a Dave
443 * Fixed some rendering problems.
445 * 85 6/03/99 10:15p Dave
446 * Put in temporary main hall screen.
448 * 84 6/02/99 6:18p Dave
449 * Fixed TNT lockup problems! Wheeeee!
451 * 83 6/01/99 3:52p Dave
452 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
453 * dead popup, pxo find player popup, pxo private room popup.
455 * 82 5/26/99 1:28p Jasenw
456 * changed coords for loading ani
458 * 81 5/26/99 11:46a Dave
459 * Added ship-blasting lighting and made the randomization of lighting
460 * much more customizable.
462 * 80 5/24/99 5:45p Dave
463 * Added detail levels to the nebula, with a decent speedup. Split nebula
464 * lightning into its own section.
482 #include "systemvars.h"
487 #include "starfield.h"
488 #include "lighting.h"
493 #include "fireballs.h"
497 #include "floating.h"
498 #include "gamesequence.h"
500 #include "optionsmenu.h"
501 #include "playermenu.h"
502 #include "trainingmenu.h"
503 #include "techmenu.h"
506 #include "hudmessage.h"
508 #include "missiongoals.h"
509 #include "missionparse.h"
514 #include "multiutil.h"
515 #include "multimsgs.h"
519 #include "freespace.h"
520 #include "managepilot.h"
522 #include "contexthelp.h"
525 #include "missionbrief.h"
526 #include "missiondebrief.h"
528 #include "missionshipchoice.h"
530 #include "hudconfig.h"
531 #include "controlsconfig.h"
532 #include "missionmessage.h"
533 #include "missiontraining.h"
535 #include "hudtarget.h"
539 #include "eventmusic.h"
540 #include "animplay.h"
541 #include "missionweaponchoice.h"
542 #include "missionlog.h"
543 #include "audiostr.h"
545 #include "missioncampaign.h"
547 #include "missionhotkey.h"
548 #include "objectsnd.h"
549 #include "cmeasure.h"
551 #include "linklist.h"
552 #include "shockwave.h"
553 #include "afterburner.h"
558 #include "stand_gui.h"
559 #include "pcxutils.h"
560 #include "hudtargetbox.h"
561 #include "multi_xfer.h"
562 #include "hudescort.h"
563 #include "multiutil.h"
566 #include "multiteamselect.h"
569 #include "readyroom.h"
570 #include "mainhallmenu.h"
571 #include "multilag.h"
573 #include "particle.h"
575 #include "multi_ingame.h"
576 #include "snazzyui.h"
577 #include "asteroid.h"
578 #include "popupdead.h"
579 #include "multi_voice.h"
580 #include "missioncmdbrief.h"
581 #include "redalert.h"
582 #include "gameplayhelp.h"
583 #include "multilag.h"
584 #include "staticrand.h"
585 #include "multi_pmsg.h"
586 #include "levelpaging.h"
587 #include "observer.h"
588 #include "multi_pause.h"
589 #include "multi_endgame.h"
590 #include "cutscenes.h"
591 #include "multi_respawn.h"
592 // #include "movie.h"
593 #include "multi_obj.h"
594 #include "multi_log.h"
596 #include "localize.h"
597 #include "osregistry.h"
598 #include "barracks.h"
599 #include "missionpause.h"
601 #include "alphacolors.h"
602 #include "objcollide.h"
605 #include "neblightning.h"
606 #include "shipcontrails.h"
609 #include "multi_dogfight.h"
610 #include "multi_rate.h"
611 #include "muzzleflash.h"
615 #include "mainhalltemp.h"
616 #include "exceptionhandler.h"
620 #include "supernova.h"
621 #include "hudshield.h"
622 // #include "names.h"
624 #include "missionloopbrief.h"
628 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
634 // 1.00.04 5/26/98 MWA -- going final (12 pm)
635 // 1.00.03 5/26/98 MWA -- going final (3 am)
636 // 1.00.02 5/25/98 MWA -- going final
637 // 1.00.01 5/25/98 MWA -- going final
638 // 0.90 5/21/98 MWA -- getting ready for final.
639 // 0.10 4/9/98. Set by MK.
641 // Demo version: (obsolete since DEMO codebase split from tree)
642 // 0.03 4/10/98 AL. Interplay rev
643 // 0.02 4/8/98 MK. Increased when this system was modified.
644 // 0.01 4/7/98? AL. First release to Interplay QA.
647 // 1.00 5/28/98 AL. First release to Interplay QA.
649 void game_level_init(int seed = -1);
650 void game_post_level_init();
651 void game_do_frame();
652 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
653 void game_reset_time();
654 void game_show_framerate(); // draws framerate in lower right corner
656 int Game_no_clear = 0;
658 int Pofview_running = 0;
659 int Nebedit_running = 0;
661 typedef struct big_expl_flash {
662 float max_flash_intensity; // max intensity
663 float cur_flash_intensity; // cur intensity
664 int flash_start; // start time
667 #define FRAME_FILTER 16
669 #define DEFAULT_SKILL_LEVEL 1
670 int Game_skill_level = DEFAULT_SKILL_LEVEL;
672 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
673 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
675 #define EXE_FNAME ("fs2.exe")
676 #define LAUNCHER_FNAME ("freespace2.exe")
678 // JAS: Code for warphole camera.
679 // Needs to be cleaned up.
680 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
681 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
682 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
683 matrix Camera_orient = IDENTITY_MATRIX;
684 float Camera_damping = 1.0f;
685 float Camera_time = 0.0f;
686 float Warpout_time = 0.0f;
687 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
688 int Warpout_sound = -1;
690 int Use_joy_mouse = 0;
691 int Use_palette_flash = 1;
693 int Use_fullscreen_at_startup = 0;
695 int Show_area_effect = 0;
696 object *Last_view_target = NULL;
698 int dogfight_blown = 0;
701 float frametimes[FRAME_FILTER];
702 float frametotal = 0.0f;
706 int Show_framerate = 0;
708 int Show_framerate = 1;
711 int Framerate_cap = 120;
714 int Show_target_debug_info = 0;
715 int Show_target_weapons = 0;
719 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
722 int Debug_octant = -1;
724 fix Game_time_compression = F1_0;
726 // if the ships.tbl the player has is valid
727 int Game_ships_tbl_valid = 0;
729 // if the weapons.tbl the player has is valid
730 int Game_weapons_tbl_valid = 0;
734 extern int Player_attacking_enabled;
738 int Pre_player_entry;
740 int Fred_running = 0;
741 char Game_current_mission_filename[MAX_FILENAME_LEN];
742 int game_single_step = 0;
743 int last_single_step=0;
745 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
746 extern int MSG_WINDOW_Y_START;
747 extern int MSG_WINDOW_HEIGHT;
749 int game_zbuffer = 1;
750 //static int Game_music_paused;
751 static int Game_paused;
755 #define EXPIRE_BAD_CHECKSUM 1
756 #define EXPIRE_BAD_TIME 2
758 extern void ssm_init();
759 extern void ssm_level_init();
760 extern void ssm_process();
762 // static variable to contain the time this version was built
763 // commented out for now until
764 // I figure out how to get the username into the file
765 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
767 // defines and variables used for dumping frame for making trailers.
769 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
770 int Debug_dump_trigger = 0;
771 int Debug_dump_frame_count;
772 int Debug_dump_frame_num = 0;
773 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
776 // amount of time to wait after the player has died before we display the death died popup
777 #define PLAYER_DIED_POPUP_WAIT 2500
778 int Player_died_popup_wait = -1;
779 int Player_multi_died_check = -1;
781 // builtin mission list stuff
783 int Game_builtin_mission_count = 6;
784 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
785 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
786 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
787 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
788 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
789 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
790 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
792 #elif defined(PD_BUILD)
793 int Game_builtin_mission_count = 4;
794 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
795 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
796 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
797 { "sm1-01", (FSB_FROM_VOLITION), "" },
798 { "sm1-05", (FSB_FROM_VOLITION), "" },
800 #elif defined(MULTIPLAYER_BETA)
801 int Game_builtin_mission_count = 17;
802 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
804 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
805 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
806 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
807 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
808 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
809 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
810 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
811 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
812 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
813 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
814 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
815 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
816 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
817 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
818 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
819 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
820 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
822 #elif defined(OEM_BUILD)
823 int Game_builtin_mission_count = 17;
824 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
825 // oem version - act 1 only
826 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
829 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
830 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
831 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
832 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
833 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
834 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
835 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
836 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
837 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
838 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
839 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
840 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
841 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
842 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
843 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
844 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
847 int Game_builtin_mission_count = 92;
848 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
849 // single player campaign
850 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
853 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
854 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
855 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
856 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
857 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
858 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
859 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
860 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
861 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
862 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
863 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
864 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
865 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
866 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
867 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
868 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
869 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
870 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
871 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
874 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
875 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
876 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
877 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
878 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
879 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
880 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
881 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
882 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
883 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
886 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
887 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
888 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
889 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
890 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
891 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
892 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
893 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
894 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
895 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
896 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
897 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
899 // multiplayer missions
902 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
922 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
927 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
933 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
936 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
939 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
956 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
957 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
958 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
959 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
964 // Internal function prototypes
965 void game_maybe_draw_mouse(float frametime);
966 void init_animating_pointer();
967 void load_animating_pointer(char *filename, int dx, int dy);
968 void unload_animating_pointer();
969 void game_do_training_checks();
970 void game_shutdown(void);
971 void game_show_event_debug(float frametime);
972 void game_event_debug_init();
974 void demo_upsell_show_screens();
975 void game_start_subspace_ambient_sound();
976 void game_stop_subspace_ambient_sound();
977 void verify_ships_tbl();
978 void verify_weapons_tbl();
979 void display_title_screen();
981 // loading background filenames
982 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
983 "LoadingBG", // GR_640
984 "2_LoadingBG" // GR_1024
988 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
989 "Loading.ani", // GR_640
990 "2_Loading.ani" // GR_1024
993 #if defined(FS2_DEMO)
994 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
998 #elif defined(OEM_BUILD)
999 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1006 char Game_CDROM_dir[MAX_PATH_LEN];
1009 // How much RAM is on this machine. Set in WinMain
1010 uint Freespace_total_ram = 0;
1013 float Game_flash_red = 0.0f;
1014 float Game_flash_green = 0.0f;
1015 float Game_flash_blue = 0.0f;
1016 float Sun_spot = 0.0f;
1017 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1019 // game shudder stuff (in ms)
1020 int Game_shudder_time = -1;
1021 int Game_shudder_total = 0;
1022 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1025 sound_env Game_sound_env;
1026 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1027 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1029 int Game_sound_env_update_timestamp;
1031 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1034 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1036 fs_builtin_mission *game_find_builtin_mission(char *filename)
1040 // look through all existing builtin missions
1041 for(idx=0; idx<Game_builtin_mission_count; idx++){
1042 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1043 return &Game_builtin_mission_list[idx];
1051 int game_get_default_skill_level()
1053 return DEFAULT_SKILL_LEVEL;
1057 void game_flash_reset()
1059 Game_flash_red = 0.0f;
1060 Game_flash_green = 0.0f;
1061 Game_flash_blue = 0.0f;
1063 Big_expl_flash.max_flash_intensity = 0.0f;
1064 Big_expl_flash.cur_flash_intensity = 0.0f;
1065 Big_expl_flash.flash_start = 0;
1068 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1069 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1071 void game_framerate_check_init()
1073 // zero critical time
1074 Gf_critical_time = 0.0f;
1077 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1078 // if this is a glide card
1079 if(gr_screen.mode == GR_GLIDE){
1081 extern GrHwConfiguration hwconfig;
1084 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1085 Gf_critical = 15.0f;
1089 Gf_critical = 10.0f;
1094 Gf_critical = 15.0f;
1097 // d3d. only care about good cards here I guess (TNT)
1099 Gf_critical = 15.0f;
1102 // if this is a glide card
1103 if(gr_screen.mode == GR_GLIDE){
1105 extern GrHwConfiguration hwconfig;
1108 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1109 Gf_critical = 25.0f;
1113 Gf_critical = 20.0f;
1118 Gf_critical = 25.0f;
1121 // d3d. only care about good cards here I guess (TNT)
1123 Gf_critical = 25.0f;
1128 extern float Framerate;
1129 void game_framerate_check()
1133 // if the current framerate is above the critical level, add frametime
1134 if(Framerate >= Gf_critical){
1135 Gf_critical_time += flFrametime;
1138 if(!Show_framerate){
1142 // display if we're above the critical framerate
1143 if(Framerate < Gf_critical){
1144 gr_set_color_fast(&Color_bright_red);
1145 gr_string(200, y_start, "Framerate warning");
1150 // display our current pct of good frametime
1151 if(f2fl(Missiontime) >= 0.0f){
1152 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1155 gr_set_color_fast(&Color_bright_green);
1157 gr_set_color_fast(&Color_bright_red);
1160 gr_printf(200, y_start, "%d%%", (int)pct);
1167 // Adds a flash effect. These can be positive or negative.
1168 // The range will get capped at around -1 to 1, so stick
1169 // with a range like that.
1170 void game_flash( float r, float g, float b )
1172 Game_flash_red += r;
1173 Game_flash_green += g;
1174 Game_flash_blue += b;
1176 if ( Game_flash_red < -1.0f ) {
1177 Game_flash_red = -1.0f;
1178 } else if ( Game_flash_red > 1.0f ) {
1179 Game_flash_red = 1.0f;
1182 if ( Game_flash_green < -1.0f ) {
1183 Game_flash_green = -1.0f;
1184 } else if ( Game_flash_green > 1.0f ) {
1185 Game_flash_green = 1.0f;
1188 if ( Game_flash_blue < -1.0f ) {
1189 Game_flash_blue = -1.0f;
1190 } else if ( Game_flash_blue > 1.0f ) {
1191 Game_flash_blue = 1.0f;
1196 // Adds a flash for Big Ship explosions
1197 // cap range from 0 to 1
1198 void big_explosion_flash(float flash)
1200 Big_expl_flash.flash_start = timestamp(1);
1204 } else if (flash < 0.0f) {
1208 Big_expl_flash.max_flash_intensity = flash;
1209 Big_expl_flash.cur_flash_intensity = 0.0f;
1212 // Amount to diminish palette towards normal, per second.
1213 #define DIMINISH_RATE 0.75f
1214 #define SUN_DIMINISH_RATE 6.00f
1218 float sn_glare_scale = 1.7f;
1221 dc_get_arg(ARG_FLOAT);
1222 sn_glare_scale = Dc_arg_float;
1225 float Supernova_last_glare = 0.0f;
1226 void game_sunspot_process(float frametime)
1230 float Sun_spot_goal = 0.0f;
1233 sn_stage = supernova_active();
1235 // sunspot differently based on supernova stage
1237 // approaching. player still in control
1240 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1243 light_get_global_dir(&light_dir, 0);
1245 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1248 // scale it some more
1249 dot = dot * (0.5f + (pct * 0.5f));
1252 Sun_spot_goal += (dot * sn_glare_scale);
1255 // draw the sun glow
1256 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1257 // draw the glow for this sun
1258 stars_draw_sun_glow(0);
1261 Supernova_last_glare = Sun_spot_goal;
1264 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1267 Sun_spot_goal = 0.9f;
1268 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1270 if(Sun_spot_goal > 1.0f){
1271 Sun_spot_goal = 1.0f;
1274 Sun_spot_goal *= sn_glare_scale;
1275 Supernova_last_glare = Sun_spot_goal;
1278 // fade to white. display dead popup
1281 Supernova_last_glare += (2.0f * flFrametime);
1282 if(Supernova_last_glare > 2.0f){
1283 Supernova_last_glare = 2.0f;
1286 Sun_spot_goal = Supernova_last_glare;
1293 // check sunspots for all suns
1294 n_lights = light_get_global_count();
1297 for(idx=0; idx<n_lights; idx++){
1298 //(vector *eye_pos, matrix *eye_orient)
1299 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1302 light_get_global_dir(&light_dir, idx);
1304 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1306 Sun_spot_goal += (float)pow(dot,85.0f);
1308 // draw the glow for this sun
1309 stars_draw_sun_glow(idx);
1311 Sun_spot_goal = 0.0f;
1317 Sun_spot_goal = 0.0f;
1321 float dec_amount = frametime*SUN_DIMINISH_RATE;
1323 if ( Sun_spot < Sun_spot_goal ) {
1324 Sun_spot += dec_amount;
1325 if ( Sun_spot > Sun_spot_goal ) {
1326 Sun_spot = Sun_spot_goal;
1328 } else if ( Sun_spot > Sun_spot_goal ) {
1329 Sun_spot -= dec_amount;
1330 if ( Sun_spot < Sun_spot_goal ) {
1331 Sun_spot = Sun_spot_goal;
1337 // Call once a frame to diminish the
1338 // flash effect to 0.
1339 void game_flash_diminish(float frametime)
1341 float dec_amount = frametime*DIMINISH_RATE;
1343 if ( Game_flash_red > 0.0f ) {
1344 Game_flash_red -= dec_amount;
1345 if ( Game_flash_red < 0.0f )
1346 Game_flash_red = 0.0f;
1348 Game_flash_red += dec_amount;
1349 if ( Game_flash_red > 0.0f )
1350 Game_flash_red = 0.0f;
1353 if ( Game_flash_green > 0.0f ) {
1354 Game_flash_green -= dec_amount;
1355 if ( Game_flash_green < 0.0f )
1356 Game_flash_green = 0.0f;
1358 Game_flash_green += dec_amount;
1359 if ( Game_flash_green > 0.0f )
1360 Game_flash_green = 0.0f;
1363 if ( Game_flash_blue > 0.0f ) {
1364 Game_flash_blue -= dec_amount;
1365 if ( Game_flash_blue < 0.0f )
1366 Game_flash_blue = 0.0f;
1368 Game_flash_blue += dec_amount;
1369 if ( Game_flash_blue > 0.0f )
1370 Game_flash_blue = 0.0f;
1373 // update big_explosion_cur_flash
1374 #define TIME_UP 1500
1375 #define TIME_DOWN 2500
1376 int duration = TIME_UP + TIME_DOWN;
1377 int time = timestamp_until(Big_expl_flash.flash_start);
1378 if (time > -duration) {
1380 if (time < TIME_UP) {
1381 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1384 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1388 if ( Use_palette_flash ) {
1390 // static int or=0, og=0, ob=0;
1392 // Change the 200 to change the color range of colors.
1393 r = fl2i( Game_flash_red*128.0f );
1394 g = fl2i( Game_flash_green*128.0f );
1395 b = fl2i( Game_flash_blue*128.0f );
1397 if ( Sun_spot > 0.0f ) {
1398 r += fl2i(Sun_spot*128.0f);
1399 g += fl2i(Sun_spot*128.0f);
1400 b += fl2i(Sun_spot*128.0f);
1403 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1404 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1405 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1406 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1409 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1410 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1411 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1413 if ( (r!=0) || (g!=0) || (b!=0) ) {
1414 gr_flash( r, g, b );
1416 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1427 void game_level_close()
1429 // De-Initialize the game subsystems
1430 message_mission_shutdown();
1431 event_music_level_close();
1432 game_stop_looped_sounds();
1434 obj_snd_level_close(); // uninit object-linked persistant sounds
1435 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1436 anim_level_close(); // stop and clean up any anim instances
1437 shockwave_level_close();
1438 fireball_level_close();
1440 mission_event_shutdown();
1441 asteroid_level_close();
1442 model_cache_reset(); // Reset/free all the model caching stuff
1443 flak_level_close(); // unload flak stuff
1444 neb2_level_close(); // shutdown gaseous nebula stuff
1447 mflash_level_close();
1449 audiostream_unpause_all();
1454 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1455 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1456 void game_level_init(int seed)
1458 // seed the random number generator
1460 // if no seed was passed, seed the generator either from the time value, or from the
1461 // netgame security flags -- ensures that all players in multiplayer game will have the
1462 // same randon number sequence (with static rand functions)
1463 if ( Game_mode & GM_NORMAL ) {
1464 Game_level_seed = time(NULL);
1466 Game_level_seed = Netgame.security;
1469 // mwa 9/17/98 -- maybe this assert isn't needed????
1470 Assert( !(Game_mode & GM_MULTIPLAYER) );
1471 Game_level_seed = seed;
1473 srand( Game_level_seed );
1475 // semirand function needs to get re-initted every time in multiplayer
1476 if ( Game_mode & GM_MULTIPLAYER ){
1482 Key_normal_game = (Game_mode & GM_NORMAL);
1485 Game_shudder_time = -1;
1487 // Initialize the game subsystems
1488 // timestamp_reset(); // Must be inited before everything else
1490 game_reset_time(); // resets time, and resets saved time too
1492 obj_init(); // Must be inited before the other systems
1493 model_free_all(); // Free all existing models
1494 mission_brief_common_init(); // Free all existing briefing/debriefing text
1495 weapon_level_init();
1496 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1498 player_level_init();
1499 shipfx_flash_init(); // Init the ship gun flash system.
1500 game_flash_reset(); // Reset the flash effect
1501 particle_init(); // Reset the particle system
1505 shield_hit_init(); // Initialize system for showing shield hits
1506 radar_mission_init();
1507 mission_init_goals();
1510 obj_snd_level_init(); // init object-linked persistant sounds
1512 shockwave_level_init();
1513 afterburner_level_init();
1514 scoring_level_init( &Player->stats );
1516 asteroid_level_init();
1517 control_config_clear_used_status();
1518 collide_ship_ship_sounds_init();
1520 Pre_player_entry = 1; // Means the player has not yet entered.
1521 Entry_delay_time = 0; // Could get overwritten in mission read.
1522 fireball_preload(); // page in warphole bitmaps
1524 flak_level_init(); // initialize flak - bitmaps, etc
1525 ct_level_init(); // initialize ships contrails, etc
1526 awacs_level_init(); // initialize AWACS
1527 beam_level_init(); // initialize beam weapons
1528 mflash_level_init();
1530 supernova_level_init();
1532 // multiplayer dogfight hack
1535 shipfx_engine_wash_level_init();
1539 Last_view_target = NULL;
1544 // campaign wasn't ended
1545 Campaign_ended_in_mission = 0;
1548 // called when a mission is over -- does server specific stuff.
1549 void freespace_stop_mission()
1552 Game_mode &= ~GM_IN_MISSION;
1555 // called at frame interval to process networking stuff
1556 void game_do_networking()
1558 Assert( Net_player != NULL );
1559 if (!(Game_mode & GM_MULTIPLAYER)){
1563 // see if this player should be reading/writing data. Bit is set when at join
1564 // screen onward until quits back to main menu.
1565 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1569 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1572 multi_pause_do_frame();
1577 // Loads the best palette for this level, based
1578 // on nebula color and hud color. You could just call palette_load_table with
1579 // the appropriate filename, but who wants to do that.
1580 void game_load_palette()
1582 char palette_filename[1024];
1584 // We only use 3 hud colors right now
1585 // Assert( HUD_config.color >= 0 );
1586 // Assert( HUD_config.color <= 2 );
1588 Assert( Mission_palette >= 0 );
1589 Assert( Mission_palette <= 98 );
1591 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1592 strcpy( palette_filename, NOX("gamepalette-subspace") );
1594 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1597 mprintf(( "Loading palette %s\n", palette_filename ));
1599 // palette_load_table(palette_filename);
1602 void game_post_level_init()
1604 // Stuff which gets called after mission is loaded. Because player isn't created until
1605 // after mission loads, some things must get initted after the level loads
1607 model_level_post_init();
1610 hud_setup_escort_list();
1611 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1617 game_event_debug_init();
1620 training_mission_init();
1621 asteroid_create_all();
1623 game_framerate_check_init();
1627 // An estimate as to how high the count passed to game_loading_callback will go.
1628 // This is just a guess, it seems to always be about the same. The count is
1629 // proportional to the code being executed, not the time, so this works good
1630 // for a bar, assuming the code does about the same thing each time you
1631 // load a level. You can find this value by looking at the return value
1632 // of game_busy_callback(NULL), which I conveniently print out to the
1633 // debug output window with the '=== ENDING LOAD ==' stuff.
1634 //#define COUNT_ESTIMATE 3706
1635 #define COUNT_ESTIMATE 1111
1637 int Game_loading_callback_inited = 0;
1639 int Game_loading_background = -1;
1640 anim * Game_loading_ani = NULL;
1641 anim_instance *Game_loading_ani_instance;
1642 int Game_loading_frame=-1;
1644 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1653 // This gets called 10x per second and count is the number of times
1654 // game_busy() has been called since the current callback function
1656 void game_loading_callback(int count)
1658 game_do_networking();
1660 Assert( Game_loading_callback_inited==1 );
1661 Assert( Game_loading_ani != NULL );
1663 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1664 if ( framenum > Game_loading_ani->total_frames-1 ) {
1665 framenum = Game_loading_ani->total_frames-1;
1666 } else if ( framenum < 0 ) {
1671 while ( Game_loading_frame < framenum ) {
1672 Game_loading_frame++;
1673 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1677 if ( cbitmap > -1 ) {
1678 if ( Game_loading_background > -1 ) {
1679 gr_set_bitmap( Game_loading_background );
1683 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1684 gr_set_bitmap( cbitmap );
1685 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1687 bm_release(cbitmap);
1693 void game_loading_callback_init()
1695 Assert( Game_loading_callback_inited==0 );
1697 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1698 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1701 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1702 Assert( Game_loading_ani != NULL );
1703 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1704 Assert( Game_loading_ani_instance != NULL );
1705 Game_loading_frame = -1;
1707 Game_loading_callback_inited = 1;
1709 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1714 void game_loading_callback_close()
1716 Assert( Game_loading_callback_inited==1 );
1718 // Make sure bar shows all the way over.
1719 game_loading_callback(COUNT_ESTIMATE);
1721 int real_count = game_busy_callback( NULL );
1724 Game_loading_callback_inited = 0;
1727 mprintf(( "=================== ENDING LOAD ================\n" ));
1728 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1729 mprintf(( "================================================\n" ));
1731 // to remove warnings in release build
1735 free_anim_instance(Game_loading_ani_instance);
1736 Game_loading_ani_instance = NULL;
1737 anim_free(Game_loading_ani);
1738 Game_loading_ani = NULL;
1740 bm_release( Game_loading_background );
1741 common_free_interface_palette(); // restore game palette
1742 Game_loading_background = -1;
1744 gr_set_font( FONT1 );
1747 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1749 void game_maybe_update_sound_environment()
1751 // do nothing for now
1754 // Assign the sound environment for the game, based on the current mission
1756 void game_assign_sound_environment()
1759 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1760 Game_sound_env.id = SND_ENV_DRUGGED;
1761 Game_sound_env.volume = 0.800f;
1762 Game_sound_env.damping = 1.188f;
1763 Game_sound_env.decay = 6.392f;
1765 } else if (Num_asteroids > 30) {
1766 Game_sound_env.id = SND_ENV_AUDITORIUM;
1767 Game_sound_env.volume = 0.603f;
1768 Game_sound_env.damping = 0.5f;
1769 Game_sound_env.decay = 4.279f;
1772 Game_sound_env = Game_default_sound_env;
1776 Game_sound_env = Game_default_sound_env;
1777 Game_sound_env_update_timestamp = timestamp(1);
1780 // function which gets called before actually entering the mission. It is broken down into a funciton
1781 // since it will get called in one place from a single player game and from another place for
1782 // a multiplayer game
1783 void freespace_mission_load_stuff()
1785 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1786 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1787 if(!(Game_mode & GM_STANDALONE_SERVER)){
1789 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1791 game_loading_callback_init();
1793 event_music_level_init(); // preloads the first 2 seconds for each event music track
1796 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1799 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1802 ship_assign_sound_all(); // assign engine sounds to ships
1803 game_assign_sound_environment(); // assign the sound environment for this mission
1806 // call function in missionparse.cpp to fixup player/ai stuff.
1807 mission_parse_fixup_players();
1810 // Load in all the bitmaps for this level
1815 game_loading_callback_close();
1817 // the only thing we need to call on the standalone for now.
1819 // call function in missionparse.cpp to fixup player/ai stuff.
1820 mission_parse_fixup_players();
1822 // Load in all the bitmaps for this level
1828 uint load_mission_load;
1829 uint load_post_level_init;
1830 uint load_mission_stuff;
1832 // tells the server to load the mission and initialize structures
1833 int game_start_mission()
1835 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1837 load_gl_init = time(NULL);
1839 load_gl_init = time(NULL) - load_gl_init;
1841 if (Game_mode & GM_MULTIPLAYER) {
1842 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1844 // clear multiplayer stats
1845 init_multiplayer_stats();
1848 load_mission_load = time(NULL);
1849 if (mission_load()) {
1850 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1851 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1852 gameseq_post_event(GS_EVENT_MAIN_MENU);
1854 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1859 load_mission_load = time(NULL) - load_mission_load;
1861 // If this is a red alert mission in campaign mode, bash wingman status
1862 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1863 red_alert_bash_wingman_status();
1866 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1867 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1868 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1869 // game_load_palette();
1872 load_post_level_init = time(NULL);
1873 game_post_level_init();
1874 load_post_level_init = time(NULL) - load_post_level_init;
1878 void Do_model_timings_test();
1879 Do_model_timings_test();
1883 load_mission_stuff = time(NULL);
1884 freespace_mission_load_stuff();
1885 load_mission_stuff = time(NULL) - load_mission_stuff;
1890 int Interface_framerate = 0;
1893 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1894 DCF_BOOL( show_framerate, Show_framerate )
1895 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1896 DCF_BOOL( show_target_weapons, Show_target_weapons )
1897 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1898 DCF_BOOL( sound, Sound_enabled )
1899 DCF_BOOL( zbuffer, game_zbuffer )
1900 DCF_BOOL( shield_system, New_shield_system )
1901 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1902 DCF_BOOL( player_attacking, Player_attacking_enabled )
1903 DCF_BOOL( show_waypoints, Show_waypoints )
1904 DCF_BOOL( show_area_effect, Show_area_effect )
1905 DCF_BOOL( show_net_stats, Show_net_stats )
1906 DCF_BOOL( log, Log_debug_output_to_file )
1907 DCF_BOOL( training_msg_method, Training_msg_method )
1908 DCF_BOOL( show_player_pos, Show_player_pos )
1909 DCF_BOOL(i_framerate, Interface_framerate )
1911 DCF(show_mem,"Toggles showing mem usage")
1914 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1915 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1916 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1917 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1923 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1925 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1926 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1930 DCF(show_cpu,"Toggles showing cpu usage")
1933 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1934 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1935 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1936 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1942 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1944 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1945 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1952 // AL 4-8-98: always allow players to display their framerate
1955 DCF_BOOL( show_framerate, Show_framerate )
1962 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1965 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1966 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1967 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1968 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1970 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" );
1971 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1973 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1976 DCF(palette_flash,"Toggles palette flash effect on/off")
1979 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1980 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1981 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1982 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1984 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1985 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1988 int Use_low_mem = 0;
1990 DCF(low_mem,"Uses low memory settings regardless of RAM")
1993 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1994 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1995 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1996 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1998 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1999 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2001 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2007 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2010 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2011 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2012 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2013 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2015 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2016 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2017 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2021 int Framerate_delay = 0;
2023 float Freespace_gamma = 1.0f;
2025 DCF(gamma,"Sets Gamma factor")
2028 dc_get_arg(ARG_FLOAT|ARG_NONE);
2029 if ( Dc_arg_type & ARG_FLOAT ) {
2030 Freespace_gamma = Dc_arg_float;
2032 dc_printf( "Gamma reset to 1.0f\n" );
2033 Freespace_gamma = 1.0f;
2035 if ( Freespace_gamma < 0.1f ) {
2036 Freespace_gamma = 0.1f;
2037 } else if ( Freespace_gamma > 5.0f ) {
2038 Freespace_gamma = 5.0f;
2040 gr_set_gamma(Freespace_gamma);
2042 char tmp_gamma_string[32];
2043 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2044 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2048 dc_printf( "Usage: gamma <float>\n" );
2049 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2050 Dc_status = 0; // don't print status if help is printed. Too messy.
2054 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2063 Game_current_mission_filename[0] = 0;
2065 // seed the random number generator
2066 Game_init_seed = time(NULL);
2067 srand( Game_init_seed );
2069 Framerate_delay = 0;
2075 extern void bm_init();
2081 // Initialize the timer before the os
2089 GetCurrentDirectory(1024, whee);
2092 getcwd (whee, 1024);
2095 strcat(whee, EXE_FNAME);
2097 //Initialize the libraries
2098 s1 = timer_get_milliseconds();
2099 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2102 e1 = timer_get_milliseconds();
2104 // time a bunch of cfopens
2106 s2 = timer_get_milliseconds();
2108 for(int idx=0; idx<10000; idx++){
2109 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2114 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2116 e2 = timer_get_milliseconds();
2119 if (Is_standalone) {
2120 std_init_standalone();
2122 os_init( Osreg_class_name, Osreg_app_name );
2123 os_set_title(Osreg_title);
2126 // initialize localization module. Make sure this is down AFTER initialzing OS.
2127 // int t1 = timer_get_milliseconds();
2130 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2132 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2135 // verify that he has a valid weapons.tbl
2136 verify_weapons_tbl();
2138 // Output version numbers to registry for auto patching purposes
2139 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2140 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2141 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2143 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2144 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2145 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2148 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2152 Asteroids_enabled = 1;
2155 /////////////////////////////
2157 /////////////////////////////
2162 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2163 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2165 if (!stricmp(ptr, NOX("no sound"))) {
2166 Cmdline_freespace_no_sound = 1;
2168 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2170 } else if (!stricmp(ptr, NOX("EAX"))) {
2175 if (!Is_standalone) {
2176 snd_init(use_a3d, use_eax);
2178 /////////////////////////////
2180 /////////////////////////////
2182 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2185 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);
2187 // fire up the UpdateLauncher executable
2189 PROCESS_INFORMATION pi;
2191 memset( &si, 0, sizeof(STARTUPINFO) );
2194 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2195 NULL, // pointer to command line string
2196 NULL, // pointer to process security attributes
2197 NULL, // pointer to thread security attributes
2198 FALSE, // handle inheritance flag
2199 CREATE_DEFAULT_ERROR_MODE, // creation flags
2200 NULL, // pointer to new environment block
2201 NULL, // pointer to current directory name
2202 &si, // pointer to STARTUPINFO
2203 &pi // pointer to PROCESS_INFORMATION
2206 // If the Launcher could not be started up, let the user know
2208 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2217 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2219 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);
2227 // check for hi res pack file
2228 int has_sparky_hi = 0;
2230 // check if sparky_hi exists -- access mode 0 means does file exist
2233 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2236 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2239 // see if we've got 32 bit in the string
2240 if(strstr(ptr, "32 bit")){
2247 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2249 // always 640 for E3
2250 gr_init(GR_640, GR_GLIDE);
2252 // regular or hi-res ?
2254 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2256 if(strstr(ptr, NOX("(1024x768)"))){
2258 gr_init(GR_1024, GR_GLIDE);
2260 gr_init(GR_640, GR_GLIDE);
2263 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2265 // always 640 for E3
2267 gr_init(GR_640, GR_DIRECT3D, depth);
2269 // regular or hi-res ?
2271 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2273 if(strstr(ptr, NOX("(1024x768)"))){
2277 gr_init(GR_1024, GR_DIRECT3D, depth);
2281 gr_init(GR_640, GR_DIRECT3D, depth);
2287 if ( Use_fullscreen_at_startup && !Is_standalone) {
2288 gr_init(GR_640, GR_DIRECTDRAW);
2290 gr_init(GR_640, GR_SOFTWARE);
2293 if ( !Is_standalone ) {
2294 gr_init(GR_640, GR_DIRECTDRAW);
2296 gr_init(GR_640, GR_SOFTWARE);
2301 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2302 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2303 gr_init(GR_1024, GR_OPENGL);
2305 gr_init(GR_640, GR_OPENGL);
2309 gr_init(GR_640, GR_SOFTWARE);
2314 extern int Gr_inited;
2315 if(trying_d3d && !Gr_inited){
2317 extern char Device_init_error[512];
2318 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2327 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2328 Freespace_gamma = (float)atof(ptr);
2329 if ( Freespace_gamma == 0.0f ) {
2330 Freespace_gamma = 1.80f;
2331 } else if ( Freespace_gamma < 0.1f ) {
2332 Freespace_gamma = 0.1f;
2333 } else if ( Freespace_gamma > 5.0f ) {
2334 Freespace_gamma = 5.0f;
2336 char tmp_gamma_string[32];
2337 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2338 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2340 gr_set_gamma(Freespace_gamma);
2342 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2345 display_title_screen();
2349 // attempt to load up master tracker registry info (login and password)
2350 Multi_tracker_id = -1;
2352 // pxo login and password
2353 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2355 nprintf(("Network","Error reading in PXO login data\n"));
2356 strcpy(Multi_tracker_login,"");
2358 strcpy(Multi_tracker_login,ptr);
2360 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2362 nprintf(("Network","Error reading PXO password\n"));
2363 strcpy(Multi_tracker_passwd,"");
2365 strcpy(Multi_tracker_passwd,ptr);
2368 // pxo squad name and password
2369 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2371 nprintf(("Network","Error reading in PXO squad name\n"));
2372 strcpy(Multi_tracker_squad_name, "");
2374 strcpy(Multi_tracker_squad_name, ptr);
2377 // If less than 48MB of RAM, use low memory model.
2378 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2379 mprintf(( "Using normal memory settings...\n" ));
2380 bm_set_low_mem(1); // Use every other frame of bitmaps
2382 mprintf(( "Using high memory settings...\n" ));
2383 bm_set_low_mem(0); // Use all frames of bitmaps
2386 // load non-darkening pixel defs
2387 palman_load_pixels();
2389 // hud shield icon stuff
2390 hud_shield_game_init();
2392 control_config_common_init(); // sets up localization stuff in the control config
2398 gamesnd_parse_soundstbl();
2403 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2408 player_controls_init();
2411 //if(!Is_standalone){
2419 ship_init(); // read in ships.tbl
2421 mission_campaign_init(); // load in the default campaign
2423 // navmap_init(); // init the navigation map system
2424 context_help_init();
2425 techroom_intel_init(); // parse species.tbl, load intel info
2427 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2428 init_animating_pointer();
2430 mission_brief_common_init(); // Mark all the briefing structures as empty.
2431 gr_font_init(); // loads up all fonts
2433 neb2_init(); // fullneb stuff
2437 player_tips_init(); // helpful tips
2440 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2441 pilot_load_pic_list();
2442 pilot_load_squad_pic_list();
2444 load_animating_pointer(NOX("cursor"), 0, 0);
2446 // initialize alpha colors
2447 alpha_colors_init();
2450 // Game_music_paused = 0;
2457 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2458 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2460 mprintf(("cfile_init() took %d\n", e1 - s1));
2461 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2464 char transfer_text[128];
2466 float Start_time = 0.0f;
2468 float Framerate = 0.0f;
2470 float Timing_total = 0.0f;
2471 float Timing_render2 = 0.0f;
2472 float Timing_render3 = 0.0f;
2473 float Timing_flip = 0.0f;
2474 float Timing_clear = 0.0f;
2476 MONITOR(NumPolysDrawn);
2482 void game_get_framerate()
2484 char text[128] = "";
2486 if ( frame_int == -1 ) {
2488 for (i=0; i<FRAME_FILTER; i++ ) {
2489 frametimes[i] = 0.0f;
2494 frametotal -= frametimes[frame_int];
2495 frametotal += flFrametime;
2496 frametimes[frame_int] = flFrametime;
2497 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2499 if ( frametotal != 0.0 ) {
2500 if ( Framecount >= FRAME_FILTER )
2501 Framerate = FRAME_FILTER / frametotal;
2503 Framerate = Framecount / frametotal;
2504 sprintf( text, NOX("FPS: %.1f"), Framerate );
2506 sprintf( text, NOX("FPS: ?") );
2510 if (Show_framerate) {
2511 gr_set_color_fast(&HUD_color_debug);
2512 gr_string( 570, 2, text );
2516 void game_show_framerate()
2520 cur_time = f2fl(timer_get_approx_seconds());
2521 if (cur_time - Start_time > 30.0f) {
2522 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2523 Start_time += 1000.0f;
2526 //mprintf(( "%s\n", text ));
2529 if ( Debug_dump_frames )
2533 // possibly show control checking info
2534 control_check_indicate();
2536 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2537 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2538 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2539 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2542 if ( Show_cpu == 1 ) {
2547 dy = gr_get_font_height() + 1;
2549 gr_set_color_fast(&HUD_color_debug);
2553 extern int D3D_textures_in;
2554 extern int D3D_textures_in_frame;
2555 extern int Glide_textures_in;
2556 extern int Glide_textures_in_frame;
2557 extern int Glide_explosion_vram;
2558 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2560 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2562 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2566 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2568 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2570 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2572 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2574 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2579 extern int Num_pairs; // Number of object pairs that were checked.
2580 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2583 extern int Num_pairs_checked; // What percent of object pairs were checked.
2584 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2586 Num_pairs_checked = 0;
2590 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2593 if ( Timing_total > 0.01f ) {
2594 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2596 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2598 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2600 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2602 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2612 dy = gr_get_font_height() + 1;
2614 gr_set_color_fast(&HUD_color_debug);
2617 extern int TotalRam;
2618 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2623 extern int Model_ram;
2624 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2628 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2630 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2632 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2636 extern int D3D_textures_in;
2637 extern int Glide_textures_in;
2638 extern int Glide_textures_in_frame;
2639 extern int Glide_explosion_vram;
2640 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2642 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2644 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2651 if ( Show_player_pos ) {
2655 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));
2658 MONITOR_INC(NumPolys, modelstats_num_polys);
2659 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2660 MONITOR_INC(NumVerts, modelstats_num_verts );
2662 modelstats_num_polys = 0;
2663 modelstats_num_polys_drawn = 0;
2664 modelstats_num_verts = 0;
2665 modelstats_num_sortnorms = 0;
2669 void game_show_standalone_framerate()
2671 float frame_rate=30.0f;
2672 if ( frame_int == -1 ) {
2674 for (i=0; i<FRAME_FILTER; i++ ) {
2675 frametimes[i] = 0.0f;
2680 frametotal -= frametimes[frame_int];
2681 frametotal += flFrametime;
2682 frametimes[frame_int] = flFrametime;
2683 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2685 if ( frametotal != 0.0 ) {
2686 if ( Framecount >= FRAME_FILTER ){
2687 frame_rate = FRAME_FILTER / frametotal;
2689 frame_rate = Framecount / frametotal;
2692 std_set_standalone_fps(frame_rate);
2696 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2697 void game_show_time_left()
2701 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2702 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2703 // checking how much time is left
2705 if ( Mission_end_time == -1 ){
2709 diff = f2i(Mission_end_time - Missiontime);
2710 // be sure to bash to 0. diff could be negative on frame that we quit mission
2715 hud_set_default_color();
2716 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2719 //========================================================================================
2720 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2721 //========================================================================================
2725 DCF(ai_pause,"Pauses ai")
2728 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2729 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2730 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2731 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2734 obj_init_all_ships_physics();
2737 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2738 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2741 DCF(single_step,"Single steps the game")
2744 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2745 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2746 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2747 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2749 last_single_step = 0; // Make so single step waits a frame before stepping
2752 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2753 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2756 DCF_BOOL(physics_pause, physics_paused)
2757 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2758 DCF_BOOL(ai_firing, Ai_firing_enabled )
2760 // Create some simple aliases to these commands...
2761 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2762 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2763 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2764 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2765 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2768 //========================================================================================
2769 //========================================================================================
2772 void game_training_pause_do()
2776 key = game_check_key();
2778 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2785 void game_increase_skill_level()
2788 if (Game_skill_level >= NUM_SKILL_LEVELS){
2789 Game_skill_level = 0;
2793 int Player_died_time;
2795 int View_percent = 100;
2798 DCF(view, "Sets the percent of the 3d view to render.")
2801 dc_get_arg(ARG_INT);
2802 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2803 View_percent = Dc_arg_int;
2805 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2811 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2815 dc_printf("View is set to %d%%\n", View_percent );
2820 // Set the clip region for the 3d rendering window
2821 void game_set_view_clip()
2823 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2824 // Set the clip region for the letterbox "dead view"
2825 int yborder = gr_screen.max_h/4;
2827 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2828 // J.S. I've changed my ways!! See the new "no constants" code!!!
2829 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2831 // Set the clip region for normal view
2832 if ( View_percent >= 100 ) {
2835 int xborder, yborder;
2837 if ( View_percent < 5 ) {
2841 float fp = i2fl(View_percent)/100.0f;
2842 int fi = fl2i(fl_sqrt(fp)*100.0f);
2843 if ( fi > 100 ) fi=100;
2845 xborder = ( gr_screen.max_w*(100-fi) )/200;
2846 yborder = ( gr_screen.max_h*(100-fi) )/200;
2848 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2854 void show_debug_stuff()
2857 int laser_count = 0, missile_count = 0;
2859 for (i=0; i<MAX_OBJECTS; i++) {
2860 if (Objects[i].type == OBJ_WEAPON){
2861 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2863 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2869 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2872 extern int Tool_enabled;
2877 int tst_bitmap = -1;
2879 float tst_offset, tst_offset_total;
2882 void game_tst_frame_pre()
2890 g3_rotate_vertex(&v, &tst_pos);
2891 g3_project_vertex(&v);
2894 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2898 // big ship? always tst
2900 // within 3000 meters
2901 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2905 // within 300 meters
2906 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2913 void game_tst_frame()
2923 tst_time = time(NULL);
2925 // load the tst bitmap
2926 switch((int)frand_range(0.0f, 3.0)){
2928 tst_bitmap = bm_load("ig_jim");
2930 mprintf(("TST 0\n"));
2934 tst_bitmap = bm_load("ig_kan");
2936 mprintf(("TST 1\n"));
2940 tst_bitmap = bm_load("ig_jim");
2942 mprintf(("TST 2\n"));
2946 tst_bitmap = bm_load("ig_kan");
2948 mprintf(("TST 3\n"));
2957 // get the tst bitmap dimensions
2959 bm_get_info(tst_bitmap, &w, &h);
2962 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2964 snd_play(&Snds[SND_VASUDAN_BUP]);
2966 // tst x and direction
2970 tst_offset_total = (float)w;
2971 tst_offset = (float)w;
2973 tst_x = (float)gr_screen.max_w;
2974 tst_offset_total = (float)-w;
2975 tst_offset = (float)w;
2983 float diff = (tst_offset_total / 0.5f) * flFrametime;
2989 tst_offset -= fl_abs(diff);
2990 } else if(tst_mode == 2){
2993 tst_offset -= fl_abs(diff);
2997 gr_set_bitmap(tst_bitmap);
2998 gr_bitmap((int)tst_x, (int)tst_y);
3001 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3005 // if we passed the switch point
3006 if(tst_offset <= 0.0f){
3011 tst_stamp = timestamp(1000);
3012 tst_offset = fl_abs(tst_offset_total);
3023 void game_tst_mark(object *objp, ship *shipp)
3032 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3035 sip = &Ship_info[shipp->ship_info_index];
3042 tst_pos = objp->pos;
3043 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3049 extern void render_shields();
3051 void player_repair_frame(float frametime)
3053 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3055 for(idx=0;idx<MAX_PLAYERS;idx++){
3058 np = &Net_players[idx];
3060 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)){
3062 // don't rearm/repair if the player is dead or dying/departing
3063 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3064 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3069 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3070 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3076 #define NUM_FRAMES_TEST 300
3077 #define NUM_MIXED_SOUNDS 16
3078 void do_timing_test(float flFrametime)
3080 static int framecount = 0;
3081 static int test_running = 0;
3082 static float test_time = 0.0f;
3084 static int snds[NUM_MIXED_SOUNDS];
3087 if ( test_running ) {
3089 test_time += flFrametime;
3090 if ( framecount >= NUM_FRAMES_TEST ) {
3092 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3093 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3098 if ( Test_begin == 1 ) {
3104 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3107 // start looping digital sounds
3108 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3109 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3116 DCF(dcf_fov, "Change the field of view")
3119 dc_get_arg(ARG_FLOAT|ARG_NONE);
3120 if ( Dc_arg_type & ARG_NONE ) {
3121 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3122 dc_printf( "Zoom factor reset\n" );
3124 if ( Dc_arg_type & ARG_FLOAT ) {
3125 if (Dc_arg_float < 0.25f) {
3126 Viewer_zoom = 0.25f;
3127 dc_printf("Zoom factor pinned at 0.25.\n");
3128 } else if (Dc_arg_float > 1.25f) {
3129 Viewer_zoom = 1.25f;
3130 dc_printf("Zoom factor pinned at 1.25.\n");
3132 Viewer_zoom = Dc_arg_float;
3138 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3141 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3145 DCF(framerate_cap, "Sets the framerate cap")
3148 dc_get_arg(ARG_INT);
3149 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3150 Framerate_cap = Dc_arg_int;
3152 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3158 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3159 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3160 dc_printf("[n] must be from 1 to 120.\n");
3164 if ( Framerate_cap )
3165 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3167 dc_printf("There is no framerate cap currently active.\n");
3171 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3172 int Show_viewing_from_self = 0;
3174 void say_view_target()
3176 object *view_target;
3178 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3179 view_target = &Objects[Player_ai->target_objnum];
3181 view_target = Player_obj;
3183 if (Game_mode & GM_DEAD) {
3184 if (Player_ai->target_objnum != -1)
3185 view_target = &Objects[Player_ai->target_objnum];
3188 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3189 if (view_target != Player_obj){
3191 char *view_target_name = NULL;
3192 switch(Objects[Player_ai->target_objnum].type) {
3194 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3197 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3198 Viewer_mode &= ~VM_OTHER_SHIP;
3200 case OBJ_JUMP_NODE: {
3201 char jump_node_name[128];
3202 strcpy(jump_node_name, XSTR( "jump node", 184));
3203 view_target_name = jump_node_name;
3204 Viewer_mode &= ~VM_OTHER_SHIP;
3213 if ( view_target_name ) {
3214 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3215 Show_viewing_from_self = 1;
3218 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3219 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3220 Show_viewing_from_self = 1;
3222 if (Show_viewing_from_self)
3223 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3228 Last_view_target = view_target;
3232 float Game_hit_x = 0.0f;
3233 float Game_hit_y = 0.0f;
3235 // Reset at the beginning of each frame
3236 void game_whack_reset()
3242 // Apply a 2d whack to the player
3243 void game_whack_apply( float x, float y )
3245 // Do some force feedback
3246 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3252 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3255 // call to apply a "shudder"
3256 void game_shudder_apply(int time, float intensity)
3258 Game_shudder_time = timestamp(time);
3259 Game_shudder_total = time;
3260 Game_shudder_intensity = intensity;
3263 #define FF_SCALE 10000
3264 void apply_hud_shake(matrix *eye_orient)
3266 if (Viewer_obj == Player_obj) {
3267 physics_info *pi = &Player_obj->phys_info;
3275 // Make eye shake due to afterburner
3276 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3279 dtime = timestamp_until(pi->afterburner_decay);
3283 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3284 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3287 // Make eye shake due to engine wash
3289 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3292 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3293 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3295 // get the intensity
3296 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3300 vm_vec_rand_vec_quick(&rand_vec);
3303 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3307 // make hud shake due to shuddering
3308 if(Game_shudder_time != -1){
3309 // if the timestamp has elapsed
3310 if(timestamp_elapsed(Game_shudder_time)){
3311 Game_shudder_time = -1;
3313 // otherwise apply some shudder
3317 dtime = timestamp_until(Game_shudder_time);
3321 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));
3322 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));
3327 vm_angles_2_matrix(&tm, &tangles);
3328 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3329 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3330 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3331 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3336 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3338 // Player's velocity just before he blew up. Used to keep camera target moving.
3339 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3341 // Set eye_pos and eye_orient based on view mode.
3342 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3346 static int last_Viewer_mode = 0;
3347 static int last_Game_mode = 0;
3348 static int last_Viewer_objnum = -1;
3350 // This code is supposed to detect camera "cuts"... like going between
3353 // determine if we need to regenerate the nebula
3354 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3355 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3356 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3357 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3358 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3359 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3360 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3361 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3362 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3365 // regenerate the nebula
3369 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3370 //mprintf(( "************** Camera cut! ************\n" ));
3371 last_Viewer_mode = Viewer_mode;
3372 last_Game_mode = Game_mode;
3374 // Camera moved. Tell stars & debris to not do blurring.
3380 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3381 player_display_packlock_view();
3384 game_set_view_clip();
3386 if (Game_mode & GM_DEAD) {
3387 vector vec_to_deader, view_pos;
3390 Viewer_mode |= VM_DEAD_VIEW;
3392 if (Player_ai->target_objnum != -1) {
3393 int view_from_player = 1;
3395 if (Viewer_mode & VM_OTHER_SHIP) {
3396 // View from target.
3397 Viewer_obj = &Objects[Player_ai->target_objnum];
3399 last_Viewer_objnum = Player_ai->target_objnum;
3401 if ( Viewer_obj->type == OBJ_SHIP ) {
3402 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3403 view_from_player = 0;
3406 last_Viewer_objnum = -1;
3409 if ( view_from_player ) {
3410 // View target from player ship.
3412 *eye_pos = Player_obj->pos;
3413 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3414 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3417 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3419 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3420 dist += flFrametime * 16.0f;
3422 vm_vec_scale(&vec_to_deader, -dist);
3423 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3425 view_pos = Player_obj->pos;
3427 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3428 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3429 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3430 Dead_player_last_vel = Player_obj->phys_info.vel;
3431 //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));
3432 } else if (Player_ai->target_objnum != -1) {
3433 view_pos = Objects[Player_ai->target_objnum].pos;
3435 // Make camera follow explosion, but gradually slow down.
3436 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3437 view_pos = Player_obj->pos;
3438 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3439 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3442 *eye_pos = Dead_camera_pos;
3444 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3446 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3451 // if supernova shockwave
3452 if(supernova_camera_cut()){
3456 // call it dead view
3457 Viewer_mode |= VM_DEAD_VIEW;
3459 // set eye pos and orient
3460 supernova_set_view(eye_pos, eye_orient);
3462 // If already blown up, these other modes can override.
3463 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3464 Viewer_mode &= ~VM_DEAD_VIEW;
3466 Viewer_obj = Player_obj;
3468 if (Viewer_mode & VM_OTHER_SHIP) {
3469 if (Player_ai->target_objnum != -1){
3470 Viewer_obj = &Objects[Player_ai->target_objnum];
3471 last_Viewer_objnum = Player_ai->target_objnum;
3473 Viewer_mode &= ~VM_OTHER_SHIP;
3474 last_Viewer_objnum = -1;
3477 last_Viewer_objnum = -1;
3480 if (Viewer_mode & VM_EXTERNAL) {
3483 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3484 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3486 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3488 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3489 vm_vec_normalize(&eye_dir);
3490 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3493 // Modify the orientation based on head orientation.
3494 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3496 } else if ( Viewer_mode & VM_CHASE ) {
3499 if ( Viewer_obj->phys_info.speed < 0.1 )
3500 move_dir = Viewer_obj->orient.fvec;
3502 move_dir = Viewer_obj->phys_info.vel;
3503 vm_vec_normalize(&move_dir);
3506 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3507 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3508 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3509 vm_vec_normalize(&eye_dir);
3511 // JAS: I added the following code because if you slew up using
3512 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3513 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3514 // call because the up and the forward vector are the same. I fixed
3515 // it by adding in a fraction of the right vector all the time to the
3517 vector tmp_up = Viewer_obj->orient.uvec;
3518 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3520 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3523 // Modify the orientation based on head orientation.
3524 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3525 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3526 *eye_pos = Camera_pos;
3528 ship * shipp = &Ships[Player_obj->instance];
3530 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3531 vm_vec_normalize(&eye_dir);
3532 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3535 // get an eye position based upon the correct type of object
3536 switch(Viewer_obj->type){
3538 // make a call to get the eye point for the player object
3539 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3542 // make a call to get the eye point for the player object
3543 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3549 #ifdef JOHNS_DEBUG_CODE
3550 john_debug_stuff(&eye_pos, &eye_orient);
3556 apply_hud_shake(eye_orient);
3558 // setup neb2 rendering
3559 neb2_render_setup(eye_pos, eye_orient);
3563 extern void ai_debug_render_stuff();
3566 int Game_subspace_effect = 0;
3567 DCF_BOOL( subspace, Game_subspace_effect );
3569 // Does everything needed to render a frame
3570 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3574 g3_start_frame(game_zbuffer);
3575 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3577 // maybe offset the HUD (jitter stuff)
3578 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3579 HUD_set_offsets(Viewer_obj, !dont_offset);
3581 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3582 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3583 // must be done before ships are rendered
3584 if ( MULTIPLAYER_CLIENT ) {
3585 shield_point_multi_setup();
3588 if ( Game_subspace_effect ) {
3589 stars_draw(0,0,0,1);
3591 stars_draw(1,1,1,0);
3594 obj_render_all(obj_render);
3595 beam_render_all(); // render all beam weapons
3596 particle_render_all(); // render particles after everything else.
3597 trail_render_all(); // render missilie trails after everything else.
3598 mflash_render_all(); // render all muzzle flashes
3600 // Why do we not show the shield effect in these modes? Seems ok.
3601 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3605 // render nebula lightning
3608 // render local player nebula
3609 neb2_render_player();
3612 ai_debug_render_stuff();
3615 #ifndef RELEASE_REAL
3616 // game_framerate_check();
3620 extern void snd_spew_debug_info();
3621 snd_spew_debug_info();
3624 //================ END OF 3D RENDERING STUFF ====================
3628 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3629 hud_maybe_clear_head_area();
3630 anim_render_all(0, flFrametime);
3633 extern int Multi_display_netinfo;
3634 if(Multi_display_netinfo){
3635 extern void multi_display_netinfo();
3636 multi_display_netinfo();
3639 game_tst_frame_pre();
3642 do_timing_test(flFrametime);
3646 extern int OO_update_index;
3647 multi_rate_display(OO_update_index, 375, 0);
3652 extern void oo_display();
3659 //#define JOHNS_DEBUG_CODE 1
3661 #ifdef JOHNS_DEBUG_CODE
3662 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3664 //if ( keyd_pressed[KEY_LSHIFT] )
3666 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3668 model_subsystem *turret = tsys->system_info;
3670 if (turret->type == SUBSYSTEM_TURRET ) {
3672 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3674 ship_model_start(tobj);
3676 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3677 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3678 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3680 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3682 ship_model_stop(tobj);
3692 // following function for dumping frames for purposes of building trailers.
3695 // function to toggle state of dumping every frame into PCX when playing the game
3696 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3700 if ( Debug_dump_frames == 0 ) {
3702 Debug_dump_frames = 15;
3703 Debug_dump_trigger = 0;
3704 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3705 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3708 Debug_dump_frames = 0;
3709 Debug_dump_trigger = 0;
3710 gr_dump_frame_stop();
3711 dc_printf( "Frame dumping is now OFF\n" );
3717 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3721 if ( Debug_dump_frames == 0 ) {
3723 Debug_dump_frames = 15;
3724 Debug_dump_trigger = 1;
3725 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3726 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3729 Debug_dump_frames = 0;
3730 Debug_dump_trigger = 0;
3731 gr_dump_frame_stop();
3732 dc_printf( "Frame dumping is now OFF\n" );
3738 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3742 if ( Debug_dump_frames == 0 ) {
3744 Debug_dump_frames = 30;
3745 Debug_dump_trigger = 0;
3746 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3747 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3750 Debug_dump_frames = 0;
3751 Debug_dump_trigger = 0;
3752 gr_dump_frame_stop();
3753 dc_printf( "Frame dumping is now OFF\n" );
3759 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3763 if ( Debug_dump_frames == 0 ) {
3765 Debug_dump_frames = 30;
3766 Debug_dump_trigger = 1;
3767 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3768 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3771 Debug_dump_frames = 0;
3772 Debug_dump_trigger = 0;
3773 gr_dump_frame_stop();
3774 dc_printf( "Triggered frame dumping is now OFF\n" );
3780 void game_maybe_dump_frame()
3782 if ( !Debug_dump_frames ){
3786 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3793 Debug_dump_frame_num++;
3799 extern int Player_dead_state;
3801 // Flip the page and time how long it took.
3802 void game_flip_page_and_time_it()
3806 t1 = timer_get_fixed_seconds();
3808 t2 = timer_get_fixed_seconds();
3810 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3811 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3814 void game_simulation_frame()
3816 // blow ships up in multiplayer dogfight
3817 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){
3818 // blow up all non-player ships
3819 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3822 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3824 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)){
3825 moveup = GET_NEXT(moveup);
3828 shipp = &Ships[Objects[moveup->objnum].instance];
3829 sip = &Ship_info[shipp->ship_info_index];
3831 // only blow up small ships
3832 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3833 // function to simply explode a ship where it is currently at
3834 ship_self_destruct( &Objects[moveup->objnum] );
3837 moveup = GET_NEXT(moveup);
3843 // process AWACS stuff - do this first thing
3846 // single player, set Player hits_this_frame to 0
3847 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3848 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3849 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3853 supernova_process();
3854 if(supernova_active() >= 5){
3858 // fire targeting lasers now so that
3859 // 1 - created this frame
3860 // 2 - collide this frame
3861 // 3 - render this frame
3862 // 4 - ignored and deleted next frame
3863 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3865 ship_process_targeting_lasers();
3867 // do this here so that it works for multiplayer
3869 // get viewer direction
3870 int viewer_direction = PHYSICS_VIEWER_REAR;
3872 if(Viewer_mode == 0){
3873 viewer_direction = PHYSICS_VIEWER_FRONT;
3875 if(Viewer_mode & VM_PADLOCK_UP){
3876 viewer_direction = PHYSICS_VIEWER_UP;
3878 else if(Viewer_mode & VM_PADLOCK_REAR){
3879 viewer_direction = PHYSICS_VIEWER_REAR;
3881 else if(Viewer_mode & VM_PADLOCK_LEFT){
3882 viewer_direction = PHYSICS_VIEWER_LEFT;
3884 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3885 viewer_direction = PHYSICS_VIEWER_RIGHT;
3888 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3890 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3893 #define VM_PADLOCK_UP (1 << 7)
3894 #define VM_PADLOCK_REAR (1 << 8)
3895 #define VM_PADLOCK_LEFT (1 << 9)
3896 #define VM_PADLOCK_RIGHT (1 << 10)
3898 // evaluate mission departures and arrivals before we process all objects.
3899 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3901 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3902 // ships/wing packets.
3903 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3904 mission_parse_eval_stuff();
3907 // if we're an observer, move ourselves seperately from the standard physics
3908 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3909 obj_observer_move(flFrametime);
3912 // move all the objects now
3913 obj_move_all(flFrametime);
3915 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3916 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3917 // ship_check_cargo_all();
3918 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3919 mission_eval_goals();
3923 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3924 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3925 training_check_objectives();
3928 // do all interpolation now
3929 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3930 // client side processing of warping in effect stages
3931 multi_do_client_warp(flFrametime);
3933 // client side movement of an observer
3934 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3935 obj_observer_move(flFrametime);
3938 // move all objects - does interpolation now as well
3939 obj_move_all(flFrametime);
3942 // only process the message queue when the player is "in" the game
3943 if ( !Pre_player_entry ){
3944 message_queue_process(); // process any messages send to the player
3947 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3948 message_maybe_distort(); // maybe distort incoming message if comms damaged
3949 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3950 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3951 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3954 if(!(Game_mode & GM_STANDALONE_SERVER)){
3955 // process some stuff every frame (before frame is rendered)
3956 emp_process_local();
3958 hud_update_frame(); // update hud systems
3960 if (!physics_paused) {
3961 // Move particle system
3962 particle_move_all(flFrametime);
3964 // Move missile trails
3965 trail_move_all(flFrametime);
3967 // process muzzle flashes
3968 mflash_process_all();
3970 // Flash the gun flashes
3971 shipfx_flash_do_frame(flFrametime);
3973 shockwave_move_all(flFrametime); // update all the shockwaves
3976 // subspace missile strikes
3979 obj_snd_do_frame(); // update the object-linked persistant sounds
3980 game_maybe_update_sound_environment();
3981 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3983 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3985 if ( Game_subspace_effect ) {
3986 game_start_subspace_ambient_sound();
3992 // Maybe render and process the dead-popup
3993 void game_maybe_do_dead_popup(float frametime)
3995 if ( popupdead_is_active() ) {
3997 int choice = popupdead_do_frame(frametime);
3999 if ( Game_mode & GM_NORMAL ) {
4003 if(game_do_cd_mission_check(Game_current_mission_filename)){
4004 gameseq_post_event(GS_EVENT_ENTER_GAME);
4006 gameseq_post_event(GS_EVENT_MAIN_MENU);
4011 gameseq_post_event(GS_EVENT_END_GAME);
4016 if(game_do_cd_mission_check(Game_current_mission_filename)){
4017 gameseq_post_event(GS_EVENT_START_GAME);
4019 gameseq_post_event(GS_EVENT_MAIN_MENU);
4023 // this should only happen during a red alert mission
4026 Assert(The_mission.red_alert);
4027 if(!The_mission.red_alert){
4029 if(game_do_cd_mission_check(Game_current_mission_filename)){
4030 gameseq_post_event(GS_EVENT_START_GAME);
4032 gameseq_post_event(GS_EVENT_MAIN_MENU);
4037 // choose the previous mission
4038 mission_campaign_previous_mission();
4040 if(game_do_cd_mission_check(Game_current_mission_filename)){
4041 gameseq_post_event(GS_EVENT_START_GAME);
4043 gameseq_post_event(GS_EVENT_MAIN_MENU);
4054 case POPUPDEAD_DO_MAIN_HALL:
4055 multi_quit_game(PROMPT_NONE,-1);
4058 case POPUPDEAD_DO_RESPAWN:
4059 multi_respawn_normal();
4060 event_music_player_respawn();
4063 case POPUPDEAD_DO_OBSERVER:
4064 multi_respawn_observer();
4065 event_music_player_respawn_as_observer();
4074 if ( leave_popup ) {
4080 // returns true if player is actually in a game_play stats
4081 int game_actually_playing()
4085 state = gameseq_get_state();
4086 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4092 // Draw the 2D HUD gauges
4093 void game_render_hud_2d()
4095 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4099 HUD_render_2d(flFrametime);
4103 // Draw the 3D-dependant HUD gauges
4104 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4106 g3_start_frame(0); // 0 = turn zbuffering off
4107 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4109 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4110 HUD_render_3d(flFrametime);
4114 game_sunspot_process(flFrametime);
4116 // Diminish the palette effect
4117 game_flash_diminish(flFrametime);
4125 int actually_playing;
4126 fix total_time1, total_time2;
4127 fix render2_time1=0, render2_time2=0;
4128 fix render3_time1=0, render3_time2=0;
4129 fix flip_time1=0, flip_time2=0;
4130 fix clear_time1=0, clear_time2=0;
4136 if (Framerate_delay) {
4137 int start_time = timer_get_milliseconds();
4138 while (timer_get_milliseconds() < start_time + Framerate_delay)
4144 demo_do_frame_start();
4146 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4151 // start timing frame
4152 timing_frame_start();
4154 total_time1 = timer_get_fixed_seconds();
4156 // var to hold which state we are in
4157 actually_playing = game_actually_playing();
4159 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4160 if (!(Game_mode & GM_STANDALONE_SERVER)){
4161 Assert( OBJ_INDEX(Player_obj) >= 0 );
4165 if (Missiontime > Entry_delay_time){
4166 Pre_player_entry = 0;
4168 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4171 // Note: These are done even before the player enters, else buffers can overflow.
4172 if (! (Game_mode & GM_STANDALONE_SERVER)){
4176 shield_frame_init();
4178 if ( Player->control_mode != PCM_NORMAL )
4181 if ( !Pre_player_entry && actually_playing ) {
4182 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4184 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4185 game_process_keys();
4187 // don't read flying controls if we're playing a demo back
4188 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4189 read_player_controls( Player_obj, flFrametime);
4193 // if we're not the master, we may have to send the server-critical ship status button_info bits
4194 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4195 multi_maybe_send_ship_status();
4200 // Reset the whack stuff
4203 // These two lines must be outside of Pre_player_entry code,
4204 // otherwise too many lights are added.
4207 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4211 game_simulation_frame();
4213 // if not actually in a game play state, then return. This condition could only be true in
4214 // a multiplayer game.
4215 if ( !actually_playing ) {
4216 Assert( Game_mode & GM_MULTIPLAYER );
4220 if (!Pre_player_entry) {
4221 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4222 clear_time1 = timer_get_fixed_seconds();
4223 // clear the screen to black
4225 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4229 clear_time2 = timer_get_fixed_seconds();
4230 render3_time1 = timer_get_fixed_seconds();
4231 game_render_frame_setup(&eye_pos, &eye_orient);
4232 game_render_frame( &eye_pos, &eye_orient );
4234 // save the eye position and orientation
4235 if ( Game_mode & GM_MULTIPLAYER ) {
4236 Net_player->s_info.eye_pos = eye_pos;
4237 Net_player->s_info.eye_orient = eye_orient;
4240 hud_show_target_model();
4242 // check to see if we should display the death died popup
4243 if(Game_mode & GM_DEAD_BLEW_UP){
4244 if(Game_mode & GM_MULTIPLAYER){
4245 // catch the situation where we're supposed to be warping out on this transition
4246 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4247 gameseq_post_event(GS_EVENT_DEBRIEF);
4248 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4249 Player_died_popup_wait = -1;
4253 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4254 Player_died_popup_wait = -1;
4260 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4261 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4262 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4263 if(!popupdead_is_active()){
4267 Player_multi_died_check = -1;
4271 render3_time2 = timer_get_fixed_seconds();
4272 render2_time1 = timer_get_fixed_seconds();
4275 game_get_framerate();
4276 game_show_framerate();
4278 game_show_time_left();
4280 // Draw the 2D HUD gauges
4281 if(supernova_active() < 3){
4282 game_render_hud_2d();
4285 game_set_view_clip();
4287 // Draw 3D HUD gauges
4288 game_render_hud_3d(&eye_pos, &eye_orient);
4292 render2_time2 = timer_get_fixed_seconds();
4294 // maybe render and process the dead popup
4295 game_maybe_do_dead_popup(flFrametime);
4297 // start timing frame
4298 timing_frame_stop();
4299 // timing_display(30, 10);
4301 // If a regular popup is active, don't flip (popup code flips)
4302 if( !popup_running_state() ){
4303 flip_time1 = timer_get_fixed_seconds();
4304 game_flip_page_and_time_it();
4305 flip_time2 = timer_get_fixed_seconds();
4309 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4312 game_show_standalone_framerate();
4316 game_do_training_checks();
4319 // process lightning (nebula only)
4322 total_time2 = timer_get_fixed_seconds();
4324 // Got some timing numbers
4325 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4326 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4327 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4328 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4329 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4332 demo_do_frame_end();
4334 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4340 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4341 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4342 // died. This resulted in screwed up death sequences.
4344 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4345 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4346 static int timer_paused=0;
4347 #if defined(TIMER_TEST) && !defined(NDEBUG)
4348 static int stop_count,start_count;
4349 static int time_stopped,time_started;
4351 int saved_timestamp_ticker = -1;
4353 void game_reset_time()
4355 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4359 // Last_time = timer_get_fixed_seconds();
4365 void game_stop_time()
4367 if (timer_paused==0) {
4369 time = timer_get_fixed_seconds();
4370 // Save how much time progressed so far in the frame so we can
4371 // use it when we unpause.
4372 Last_delta_time = time - Last_time;
4374 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4375 if (Last_delta_time < 0) {
4376 #if defined(TIMER_TEST) && !defined(NDEBUG)
4377 Int3(); //get Matt!!!!
4379 Last_delta_time = 0;
4381 #if defined(TIMER_TEST) && !defined(NDEBUG)
4382 time_stopped = time;
4385 // Stop the timer_tick stuff...
4386 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4387 saved_timestamp_ticker = timestamp_ticker;
4391 #if defined(TIMER_TEST) && !defined(NDEBUG)
4396 void game_start_time()
4399 Assert(timer_paused >= 0);
4400 if (timer_paused==0) {
4402 time = timer_get_fixed_seconds();
4403 #if defined(TIMER_TEST) && !defined(NDEBUG)
4405 Int3(); //get Matt!!!!
4408 // Take current time, and set it backwards to account for time
4409 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4410 // will be correct when it goes to calculate the frametime next
4412 Last_time = time - Last_delta_time;
4413 #if defined(TIMER_TEST) && !defined(NDEBUG)
4414 time_started = time;
4417 // Restore the timer_tick stuff...
4418 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4419 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4420 timestamp_ticker = saved_timestamp_ticker;
4421 saved_timestamp_ticker = -1;
4424 #if defined(TIMER_TEST) && !defined(NDEBUG)
4430 void game_set_frametime(int state)
4433 float frame_cap_diff;
4435 thistime = timer_get_fixed_seconds();
4437 if ( Last_time == 0 )
4438 Frametime = F1_0 / 30;
4440 Frametime = thistime - Last_time;
4442 // Frametime = F1_0 / 30;
4444 fix debug_frametime = Frametime; // Just used to display frametime.
4446 // If player hasn't entered mission yet, make frame take 1/4 second.
4447 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4450 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4452 fix frame_speed = F1_0 / Debug_dump_frames;
4454 if (Frametime > frame_speed ){
4455 nprintf(("warning","slow frame: %x\n",Frametime));
4458 thistime = timer_get_fixed_seconds();
4459 Frametime = thistime - Last_time;
4460 } while (Frametime < frame_speed );
4462 Frametime = frame_speed;
4466 Assert( Framerate_cap > 0 );
4468 // Cap the framerate so it doesn't get too high.
4472 cap = F1_0/Framerate_cap;
4473 if (Frametime < cap) {
4474 thistime = cap - Frametime;
4475 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4476 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4478 thistime = timer_get_fixed_seconds();
4482 if((Game_mode & GM_STANDALONE_SERVER) &&
4483 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4485 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4486 Sleep((DWORD)(frame_cap_diff*1000));
4488 thistime += fl2f((frame_cap_diff));
4490 Frametime = thistime - Last_time;
4493 // If framerate is too low, cap it.
4494 if (Frametime > MAX_FRAMETIME) {
4496 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4498 // to remove warnings in release build
4499 debug_frametime = fl2f(flFrametime);
4501 Frametime = MAX_FRAMETIME;
4504 Frametime = fixmul(Frametime, Game_time_compression);
4506 Last_time = thistime;
4507 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4509 flFrametime = f2fl(Frametime);
4510 //if(!(Game_mode & GM_PLAYING_DEMO)){
4511 timestamp_inc(flFrametime);
4513 /* if ((Framecount > 0) && (Framecount < 10)) {
4514 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4519 // This is called from game_do_frame(), and from navmap_do_frame()
4520 void game_update_missiontime()
4522 // TODO JAS: Put in if and move this into game_set_frametime,
4523 // fix navmap to call game_stop/start_time
4524 //if ( !timer_paused )
4525 Missiontime += Frametime;
4528 void game_do_frame()
4530 game_set_frametime(GS_STATE_GAME_PLAY);
4531 game_update_missiontime();
4533 if (Game_mode & GM_STANDALONE_SERVER) {
4534 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4537 if ( game_single_step && (last_single_step == game_single_step) ) {
4538 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4539 while( key_checkch() == 0 )
4541 os_set_title( XSTR( "FreeSpace", 171) );
4542 Last_time = timer_get_fixed_seconds();
4545 last_single_step = game_single_step;
4547 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4548 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4552 Keep_mouse_centered = 0;
4553 monitor_update(); // Update monitor variables
4556 void multi_maybe_do_frame()
4558 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4563 int Joymouse_button_status = 0;
4565 // Flush all input devices
4573 Joymouse_button_status = 0;
4575 //mprintf(("Game flush!\n" ));
4578 // function for multiplayer only which calls game_do_state_common() when running the
4580 void game_do_dc_networking()
4582 Assert( Game_mode & GM_MULTIPLAYER );
4584 game_do_state_common( gameseq_get_state() );
4587 // Call this whenever in a loop, or when you need to check for a keystroke.
4588 int game_check_key()
4594 // convert keypad enter to normal enter
4595 if ((k & KEY_MASK) == KEY_PADENTER)
4596 k = (k & ~KEY_MASK) | KEY_ENTER;
4603 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4604 static int Demo_show_trailer_timestamp = 0;
4606 void demo_reset_trailer_timer()
4608 Demo_show_trailer_timestamp = timer_get_milliseconds();
4611 void demo_maybe_show_trailer(int k)
4614 // if key pressed, reset demo trailer timer
4616 demo_reset_trailer_timer();
4620 // if mouse moved, reset demo trailer timer
4623 mouse_get_delta(&dx, &dy);
4624 if ( (dx > 0) || (dy > 0) ) {
4625 demo_reset_trailer_timer();
4629 // if joystick has moved, reset demo trailer timer
4632 joy_get_delta(&dx, &dy);
4633 if ( (dx > 0) || (dy > 0) ) {
4634 demo_reset_trailer_timer();
4638 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4639 // the low-level code. Ugly, I know... but was the simplest and most
4642 // if 30 seconds since last demo trailer time reset, launch movie
4643 if ( os_foreground() ) {
4644 int now = timer_get_milliseconds();
4645 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4646 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4648 movie_play( NOX("fstrailer2.mve") );
4649 demo_reset_trailer_timer();
4657 // same as game_check_key(), except this is used while actually in the game. Since there
4658 // generally are differences between game control keys and general UI keys, makes sense to
4659 // have seperate functions for each case. If you are not checking a game control while in a
4660 // mission, you should probably be using game_check_key() instead.
4665 if (!os_foreground()) {
4670 // If we're in a single player game, pause it.
4671 if (!(Game_mode & GM_MULTIPLAYER)){
4672 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4673 game_process_pause_key();
4681 demo_maybe_show_trailer(k);
4684 // Move the mouse cursor with the joystick.
4685 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4686 // Move the mouse cursor with the joystick
4690 joy_get_pos( &jx, &jy, &jz, &jr );
4692 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4693 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4696 mouse_get_real_pos( &mx, &my );
4697 mouse_set_pos( mx+dx, my+dy );
4702 m = mouse_down(MOUSE_LEFT_BUTTON);
4704 if ( j != Joymouse_button_status ) {
4705 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4706 Joymouse_button_status = j;
4708 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4709 } else if ( (!j) && (m) ) {
4710 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4715 // if we should be ignoring keys because of some multiplayer situations
4716 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4720 // If a popup is running, don't process all the Fn keys
4721 if( popup_active() ) {
4725 state = gameseq_get_state();
4727 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4730 case KEY_DEBUGGED + KEY_BACKSP:
4735 launch_context_help();
4740 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4742 // don't allow f2 while warping out in multiplayer
4743 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4748 case GS_STATE_INITIAL_PLAYER_SELECT:
4749 case GS_STATE_OPTIONS_MENU:
4750 case GS_STATE_HUD_CONFIG:
4751 case GS_STATE_CONTROL_CONFIG:
4752 case GS_STATE_DEATH_DIED:
4753 case GS_STATE_DEATH_BLEW_UP:
4754 case GS_STATE_VIEW_MEDALS:
4758 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4765 // hotkey selection screen -- only valid from briefing and beyond.
4768 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) ) {
4769 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4775 case KEY_DEBUGGED + KEY_F3:
4776 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4779 case KEY_DEBUGGED + KEY_F4:
4780 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4784 if(Game_mode & GM_MULTIPLAYER){
4785 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4786 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4790 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4791 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4797 case KEY_ESC | KEY_SHIFTED:
4798 // make sure to quit properly out of multiplayer
4799 if(Game_mode & GM_MULTIPLAYER){
4800 multi_quit_game(PROMPT_NONE);
4803 gameseq_post_event( GS_EVENT_QUIT_GAME );
4808 case KEY_DEBUGGED + KEY_P:
4811 case KEY_PRINT_SCRN:
4813 static int counter = 0;
4818 sprintf( tmp_name, NOX("screen%02d"), counter );
4820 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4821 gr_print_screen(tmp_name);
4829 case KEY_SHIFTED | KEY_ENTER: {
4831 #if !defined(NDEBUG)
4833 if ( Game_mode & GM_NORMAL ){
4837 // if we're in multiplayer mode, do some special networking
4838 if(Game_mode & GM_MULTIPLAYER){
4839 debug_console(game_do_dc_networking);
4846 if ( Game_mode & GM_NORMAL )
4860 gameseq_post_event(GS_EVENT_QUIT_GAME);
4863 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4866 void camera_set_position( vector *pos )
4871 void camera_set_orient( matrix *orient )
4873 Camera_orient = *orient;
4876 void camera_set_velocity( vector *vel, int instantaneous )
4878 Camera_desired_velocity.x = 0.0f;
4879 Camera_desired_velocity.y = 0.0f;
4880 Camera_desired_velocity.z = 0.0f;
4882 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4883 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4884 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4886 if ( instantaneous ) {
4887 Camera_velocity = Camera_desired_velocity;
4895 vector new_vel, delta_pos;
4897 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4898 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4899 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4901 Camera_velocity = new_vel;
4903 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4905 vm_vec_add2( &Camera_pos, &delta_pos );
4907 float ot = Camera_time+0.0f;
4909 Camera_time += flFrametime;
4911 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4914 tmp.z = 4.739f; // always go this fast forward.
4916 // pick x and y velocities so they are always on a
4917 // circle with a 25 m radius.
4919 float tmp_angle = frand()*PI2;
4921 tmp.x = 22.0f * (float)sin(tmp_angle);
4922 tmp.y = -22.0f * (float)cos(tmp_angle);
4924 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4926 //mprintf(( "Changing velocity!\n" ));
4927 camera_set_velocity( &tmp, 0 );
4930 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4931 vector tmp = { 0.0f, 0.0f, 0.0f };
4932 camera_set_velocity( &tmp, 0 );
4937 void end_demo_campaign_do()
4939 #if defined(FS2_DEMO)
4940 // show upsell screens
4941 demo_upsell_show_screens();
4942 #elif defined(OEM_BUILD)
4943 // show oem upsell screens
4944 oem_upsell_show_screens();
4947 // drop into main hall
4948 gameseq_post_event( GS_EVENT_MAIN_MENU );
4951 // All code to process events. This is the only place
4952 // that you should change the state of the game.
4953 void game_process_event( int current_state, int event )
4955 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4958 case GS_EVENT_SIMULATOR_ROOM:
4959 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4962 case GS_EVENT_MAIN_MENU:
4963 gameseq_set_state(GS_STATE_MAIN_MENU);
4966 case GS_EVENT_OPTIONS_MENU:
4967 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4970 case GS_EVENT_BARRACKS_MENU:
4971 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4974 case GS_EVENT_TECH_MENU:
4975 gameseq_set_state(GS_STATE_TECH_MENU);
4978 case GS_EVENT_TRAINING_MENU:
4979 gameseq_set_state(GS_STATE_TRAINING_MENU);
4982 case GS_EVENT_START_GAME:
4983 Select_default_ship = 0;
4984 Player_multi_died_check = -1;
4985 gameseq_set_state(GS_STATE_CMD_BRIEF);
4988 case GS_EVENT_START_BRIEFING:
4989 gameseq_set_state(GS_STATE_BRIEFING);
4992 case GS_EVENT_DEBRIEF:
4993 // did we end the campaign in the main freespace 2 single player campaign?
4994 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4995 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4997 gameseq_set_state(GS_STATE_DEBRIEF);
5000 Player_multi_died_check = -1;
5003 case GS_EVENT_SHIP_SELECTION:
5004 gameseq_set_state( GS_STATE_SHIP_SELECT );
5007 case GS_EVENT_WEAPON_SELECTION:
5008 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5011 case GS_EVENT_ENTER_GAME:
5013 // maybe start recording a demo
5015 demo_start_record("test.fsd");
5019 if (Game_mode & GM_MULTIPLAYER) {
5020 // if we're respawning, make sure we change the view mode so that the hud shows up
5021 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5025 gameseq_set_state(GS_STATE_GAME_PLAY);
5027 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5030 Player_multi_died_check = -1;
5032 // clear multiplayer button info
5033 extern button_info Multi_ship_status_bi;
5034 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5036 Start_time = f2fl(timer_get_approx_seconds());
5038 mprintf(("Entering game at time = %7.3f\n", Start_time));
5042 case GS_EVENT_START_GAME_QUICK:
5043 Select_default_ship = 1;
5044 gameseq_post_event(GS_EVENT_ENTER_GAME);
5048 case GS_EVENT_END_GAME:
5049 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5050 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5051 gameseq_set_state(GS_STATE_MAIN_MENU);
5056 Player_multi_died_check = -1;
5059 case GS_EVENT_QUIT_GAME:
5060 main_hall_stop_music();
5061 main_hall_stop_ambient();
5062 gameseq_set_state(GS_STATE_QUIT_GAME);
5064 Player_multi_died_check = -1;
5067 case GS_EVENT_GAMEPLAY_HELP:
5068 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5071 case GS_EVENT_PAUSE_GAME:
5072 gameseq_push_state(GS_STATE_GAME_PAUSED);
5075 case GS_EVENT_DEBUG_PAUSE_GAME:
5076 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5079 case GS_EVENT_TRAINING_PAUSE:
5080 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5083 case GS_EVENT_PREVIOUS_STATE:
5084 gameseq_pop_state();
5087 case GS_EVENT_TOGGLE_FULLSCREEN:
5088 #ifndef HARDWARE_ONLY
5090 if ( gr_screen.mode == GR_SOFTWARE ) {
5091 gr_init( GR_640, GR_DIRECTDRAW );
5092 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5093 gr_init( GR_640, GR_SOFTWARE );
5099 case GS_EVENT_TOGGLE_GLIDE:
5101 if ( gr_screen.mode != GR_GLIDE ) {
5102 gr_init( GR_640, GR_GLIDE );
5104 gr_init( GR_640, GR_SOFTWARE );
5109 case GS_EVENT_LOAD_MISSION_MENU:
5110 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5113 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5114 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5117 case GS_EVENT_HUD_CONFIG:
5118 gameseq_push_state( GS_STATE_HUD_CONFIG );
5121 case GS_EVENT_CONTROL_CONFIG:
5122 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5125 case GS_EVENT_DEATH_DIED:
5126 gameseq_set_state( GS_STATE_DEATH_DIED );
5129 case GS_EVENT_DEATH_BLEW_UP:
5130 if ( current_state == GS_STATE_DEATH_DIED ) {
5131 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5132 event_music_player_death();
5134 // multiplayer clients set their extra check here
5135 if(Game_mode & GM_MULTIPLAYER){
5136 // set the multi died absolute last chance check
5137 Player_multi_died_check = time(NULL);
5140 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5144 case GS_EVENT_NEW_CAMPAIGN:
5145 if (!mission_load_up_campaign()){
5146 readyroom_continue_campaign();
5149 Player_multi_died_check = -1;
5152 case GS_EVENT_CAMPAIGN_CHEAT:
5153 if (!mission_load_up_campaign()){
5155 // bash campaign value
5156 extern char Main_hall_campaign_cheat[512];
5159 // look for the mission
5160 for(idx=0; idx<Campaign.num_missions; idx++){
5161 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5162 Campaign.next_mission = idx;
5163 Campaign.prev_mission = idx - 1;
5170 readyroom_continue_campaign();
5173 Player_multi_died_check = -1;
5176 case GS_EVENT_CAMPAIGN_ROOM:
5177 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5180 case GS_EVENT_CMD_BRIEF:
5181 gameseq_set_state(GS_STATE_CMD_BRIEF);
5184 case GS_EVENT_RED_ALERT:
5185 gameseq_set_state(GS_STATE_RED_ALERT);
5188 case GS_EVENT_CREDITS:
5189 gameseq_set_state( GS_STATE_CREDITS );
5192 case GS_EVENT_VIEW_MEDALS:
5193 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5196 case GS_EVENT_SHOW_GOALS:
5197 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5200 case GS_EVENT_HOTKEY_SCREEN:
5201 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5204 // multiplayer stuff follow these comments
5206 case GS_EVENT_MULTI_JOIN_GAME:
5207 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5210 case GS_EVENT_MULTI_HOST_SETUP:
5211 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5214 case GS_EVENT_MULTI_CLIENT_SETUP:
5215 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5218 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5219 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5222 case GS_EVENT_MULTI_STD_WAIT:
5223 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5226 case GS_EVENT_STANDALONE_MAIN:
5227 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5230 case GS_EVENT_MULTI_PAUSE:
5231 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5234 case GS_EVENT_INGAME_PRE_JOIN:
5235 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5238 case GS_EVENT_EVENT_DEBUG:
5239 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5242 // Start a warpout where player automatically goes 70 no matter what
5243 // and can't cancel out of it.
5244 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5245 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5247 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5248 Player->saved_viewer_mode = Viewer_mode;
5249 Player->control_mode = PCM_WARPOUT_STAGE1;
5250 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5251 Warpout_time = 0.0f; // Start timer!
5254 case GS_EVENT_PLAYER_WARPOUT_START:
5255 if ( Player->control_mode != PCM_NORMAL ) {
5256 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5258 Player->saved_viewer_mode = Viewer_mode;
5259 Player->control_mode = PCM_WARPOUT_STAGE1;
5260 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5261 Warpout_time = 0.0f; // Start timer!
5262 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5266 case GS_EVENT_PLAYER_WARPOUT_STOP:
5267 if ( Player->control_mode != PCM_NORMAL ) {
5268 if ( !Warpout_forced ) { // cannot cancel forced warpout
5269 Player->control_mode = PCM_NORMAL;
5270 Viewer_mode = Player->saved_viewer_mode;
5271 hud_subspace_notify_abort();
5272 mprintf(( "Player put back to normal mode.\n" ));
5273 if ( Warpout_sound > -1 ) {
5274 snd_stop( Warpout_sound );
5281 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5282 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5283 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5284 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5286 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5287 shipfx_warpout_start( Player_obj );
5288 Player->control_mode = PCM_WARPOUT_STAGE2;
5289 Player->saved_viewer_mode = Viewer_mode;
5290 Viewer_mode |= VM_WARP_CHASE;
5292 vector tmp = Player_obj->pos;
5294 ship_get_eye( &tmp, &tmp_m, Player_obj );
5295 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5296 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5297 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5299 camera_set_position( &tmp );
5300 camera_set_orient( &Player_obj->orient );
5301 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5303 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5304 camera_set_velocity( &tmp_vel, 1);
5308 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5309 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5310 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5311 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5313 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5314 Player->control_mode = PCM_WARPOUT_STAGE3;
5318 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5319 mprintf(( "Player warped out. Going to debriefing!\n" ));
5320 Player->control_mode = PCM_NORMAL;
5321 Viewer_mode = Player->saved_viewer_mode;
5324 // we have a special debriefing screen for multiplayer furballs
5325 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5326 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5328 // do the normal debriefing for all other situations
5330 gameseq_post_event(GS_EVENT_DEBRIEF);
5334 case GS_EVENT_STANDALONE_POSTGAME:
5335 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5338 case GS_EVENT_INITIAL_PLAYER_SELECT:
5339 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5342 case GS_EVENT_GAME_INIT:
5343 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5344 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5346 // see if the command line option has been set to use the last pilot, and act acoordingly
5347 if( player_select_get_last_pilot() ) {
5348 // always enter the main menu -- do the automatic network startup stuff elsewhere
5349 // so that we still have valid checks for networking modes, etc.
5350 gameseq_set_state(GS_STATE_MAIN_MENU);
5352 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5357 case GS_EVENT_MULTI_MISSION_SYNC:
5358 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5361 case GS_EVENT_MULTI_START_GAME:
5362 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5365 case GS_EVENT_MULTI_HOST_OPTIONS:
5366 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5369 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5370 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5373 case GS_EVENT_TEAM_SELECT:
5374 gameseq_set_state(GS_STATE_TEAM_SELECT);
5377 case GS_EVENT_END_CAMPAIGN:
5378 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5381 case GS_EVENT_END_DEMO:
5382 gameseq_set_state(GS_STATE_END_DEMO);
5385 case GS_EVENT_LOOP_BRIEF:
5386 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5395 // Called when a state is being left.
5396 // The current state is still at old_state, but as soon as
5397 // this function leaves, then the current state will become
5398 // new state. You should never try to change the state
5399 // in here... if you think you need to, you probably really
5400 // need to post an event, not change the state.
5401 void game_leave_state( int old_state, int new_state )
5403 int end_mission = 1;
5405 switch (new_state) {
5406 case GS_STATE_GAME_PAUSED:
5407 case GS_STATE_DEBUG_PAUSED:
5408 case GS_STATE_OPTIONS_MENU:
5409 case GS_STATE_CONTROL_CONFIG:
5410 case GS_STATE_MISSION_LOG_SCROLLBACK:
5411 case GS_STATE_DEATH_DIED:
5412 case GS_STATE_SHOW_GOALS:
5413 case GS_STATE_HOTKEY_SCREEN:
5414 case GS_STATE_MULTI_PAUSED:
5415 case GS_STATE_TRAINING_PAUSED:
5416 case GS_STATE_EVENT_DEBUG:
5417 case GS_STATE_GAMEPLAY_HELP:
5418 end_mission = 0; // these events shouldn't end a mission
5422 switch (old_state) {
5423 case GS_STATE_BRIEFING:
5424 brief_stop_voices();
5425 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5426 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5427 && (new_state != GS_STATE_TEAM_SELECT) ){
5428 common_select_close();
5429 if ( new_state == GS_STATE_MAIN_MENU ) {
5430 freespace_stop_mission();
5434 // COMMAND LINE OPTION
5435 if (Cmdline_multi_stream_chat_to_file){
5436 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5437 cfclose(Multi_chat_stream);
5441 case GS_STATE_DEBRIEF:
5442 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5447 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5448 multi_df_debrief_close();
5451 case GS_STATE_LOAD_MISSION_MENU:
5452 mission_load_menu_close();
5455 case GS_STATE_SIMULATOR_ROOM:
5459 case GS_STATE_CAMPAIGN_ROOM:
5460 campaign_room_close();
5463 case GS_STATE_CMD_BRIEF:
5464 if (new_state == GS_STATE_OPTIONS_MENU) {
5469 if (new_state == GS_STATE_MAIN_MENU)
5470 freespace_stop_mission();
5475 case GS_STATE_RED_ALERT:
5479 case GS_STATE_SHIP_SELECT:
5480 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5481 new_state != GS_STATE_HOTKEY_SCREEN &&
5482 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5483 common_select_close();
5484 if ( new_state == GS_STATE_MAIN_MENU ) {
5485 freespace_stop_mission();
5490 case GS_STATE_WEAPON_SELECT:
5491 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5492 new_state != GS_STATE_HOTKEY_SCREEN &&
5493 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5494 common_select_close();
5495 if ( new_state == GS_STATE_MAIN_MENU ) {
5496 freespace_stop_mission();
5501 case GS_STATE_TEAM_SELECT:
5502 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5503 new_state != GS_STATE_HOTKEY_SCREEN &&
5504 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5505 common_select_close();
5506 if ( new_state == GS_STATE_MAIN_MENU ) {
5507 freespace_stop_mission();
5512 case GS_STATE_MAIN_MENU:
5513 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5520 case GS_STATE_OPTIONS_MENU:
5521 //game_start_time();
5522 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5523 multi_join_clear_game_list();
5525 options_menu_close();
5528 case GS_STATE_BARRACKS_MENU:
5529 if(new_state != GS_STATE_VIEW_MEDALS){
5534 case GS_STATE_MISSION_LOG_SCROLLBACK:
5535 hud_scrollback_close();
5538 case GS_STATE_TRAINING_MENU:
5539 training_menu_close();
5542 case GS_STATE_GAME_PLAY:
5543 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5544 player_save_target_and_weapon_link_prefs();
5545 game_stop_looped_sounds();
5548 sound_env_disable();
5549 joy_ff_stop_effects();
5551 // stop game time under certain conditions
5552 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5557 // shut down any recording or playing demos
5562 // when in multiplayer and going back to the main menu, send a leave game packet
5563 // right away (before calling stop mission). stop_mission was taking to long to
5564 // close mission down and I want people to get notified ASAP.
5565 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5566 multi_quit_game(PROMPT_NONE);
5569 freespace_stop_mission();
5570 Game_time_compression = F1_0;
5574 case GS_STATE_TECH_MENU:
5578 case GS_STATE_TRAINING_PAUSED:
5579 Training_num_lines = 0;
5580 // fall through to GS_STATE_GAME_PAUSED
5582 case GS_STATE_GAME_PAUSED:
5584 if ( end_mission ) {
5589 case GS_STATE_DEBUG_PAUSED:
5592 pause_debug_close();
5596 case GS_STATE_HUD_CONFIG:
5600 // join/start a game
5601 case GS_STATE_MULTI_JOIN_GAME:
5602 if(new_state != GS_STATE_OPTIONS_MENU){
5603 multi_join_game_close();
5607 case GS_STATE_MULTI_HOST_SETUP:
5608 case GS_STATE_MULTI_CLIENT_SETUP:
5609 // if this is just the host going into the options screen, don't do anything
5610 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5614 // close down the proper state
5615 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5616 multi_create_game_close();
5618 multi_game_client_setup_close();
5621 // COMMAND LINE OPTION
5622 if (Cmdline_multi_stream_chat_to_file){
5623 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5624 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5625 cfclose(Multi_chat_stream);
5630 case GS_STATE_CONTROL_CONFIG:
5631 control_config_close();
5634 case GS_STATE_DEATH_DIED:
5635 Game_mode &= ~GM_DEAD_DIED;
5637 // early end while respawning or blowing up in a multiplayer game
5638 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5640 freespace_stop_mission();
5644 case GS_STATE_DEATH_BLEW_UP:
5645 Game_mode &= ~GM_DEAD_BLEW_UP;
5647 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5648 // to determine if I should do anything.
5649 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5651 freespace_stop_mission();
5654 // if we are not respawing as an observer or as a player, our new state will not
5655 // be gameplay state.
5656 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5657 game_stop_time(); // hasn't been called yet!!
5658 freespace_stop_mission();
5664 case GS_STATE_CREDITS:
5668 case GS_STATE_VIEW_MEDALS:
5672 case GS_STATE_SHOW_GOALS:
5673 mission_show_goals_close();
5676 case GS_STATE_HOTKEY_SCREEN:
5677 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5678 mission_hotkey_close();
5682 case GS_STATE_MULTI_MISSION_SYNC:
5683 // if we're moving into the options menu, don't do anything
5684 if(new_state == GS_STATE_OPTIONS_MENU){
5688 Assert( Game_mode & GM_MULTIPLAYER );
5690 if ( new_state == GS_STATE_GAME_PLAY ){
5691 // palette_restore_palette();
5693 // change a couple of flags to indicate our state!!!
5694 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5695 send_netplayer_update_packet();
5697 // set the game mode
5698 Game_mode |= GM_IN_MISSION;
5702 case GS_STATE_VIEW_CUTSCENES:
5703 cutscenes_screen_close();
5706 case GS_STATE_MULTI_STD_WAIT:
5707 multi_standalone_wait_close();
5710 case GS_STATE_STANDALONE_MAIN:
5711 standalone_main_close();
5712 if(new_state == GS_STATE_MULTI_STD_WAIT){
5713 init_multiplayer_stats();
5717 case GS_STATE_MULTI_PAUSED:
5718 // if ( end_mission ){
5723 case GS_STATE_INGAME_PRE_JOIN:
5724 multi_ingame_select_close();
5727 case GS_STATE_STANDALONE_POSTGAME:
5728 multi_standalone_postgame_close();
5731 case GS_STATE_INITIAL_PLAYER_SELECT:
5732 player_select_close();
5735 case GS_STATE_MULTI_START_GAME:
5736 multi_start_game_close();
5739 case GS_STATE_MULTI_HOST_OPTIONS:
5740 multi_host_options_close();
5743 case GS_STATE_END_OF_CAMPAIGN:
5744 mission_campaign_end_close();
5747 case GS_STATE_LOOP_BRIEF:
5753 // Called when a state is being entered.
5754 // The current state is set to the state we're entering at
5755 // this point, and old_state is set to the state we're coming
5756 // from. You should never try to change the state
5757 // in here... if you think you need to, you probably really
5758 // need to post an event, not change the state.
5760 void game_enter_state( int old_state, int new_state )
5762 switch (new_state) {
5763 case GS_STATE_MAIN_MENU:
5764 // in multiplayer mode, be sure that we are not doing networking anymore.
5765 if ( Game_mode & GM_MULTIPLAYER ) {
5766 Assert( Net_player != NULL );
5767 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5770 Game_time_compression = F1_0;
5772 // determine which ship this guy is currently based on
5773 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5776 if (Player->on_bastion) {
5784 case GS_STATE_BRIEFING:
5785 main_hall_stop_music();
5786 main_hall_stop_ambient();
5788 if (Game_mode & GM_NORMAL) {
5789 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5790 // MWA: or from options or hotkey screens
5791 // JH: or if the command brief state already did this
5792 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5793 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5794 && (old_state != GS_STATE_CMD_BRIEF) ) {
5795 if ( !game_start_mission() ) // this should put us into a new state on failure!
5799 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5800 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5801 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5803 Game_time_compression = F1_0;
5805 if ( red_alert_mission() ) {
5806 gameseq_post_event(GS_EVENT_RED_ALERT);
5813 case GS_STATE_DEBRIEF:
5814 game_stop_looped_sounds();
5815 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5816 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5821 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5822 multi_df_debrief_init();
5825 case GS_STATE_LOAD_MISSION_MENU:
5826 mission_load_menu_init();
5829 case GS_STATE_SIMULATOR_ROOM:
5833 case GS_STATE_CAMPAIGN_ROOM:
5834 campaign_room_init();
5837 case GS_STATE_RED_ALERT:
5838 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5842 case GS_STATE_CMD_BRIEF: {
5843 int team_num = 0; // team number used as index for which cmd brief to use.
5845 if (old_state == GS_STATE_OPTIONS_MENU) {
5849 main_hall_stop_music();
5850 main_hall_stop_ambient();
5852 if (Game_mode & GM_NORMAL) {
5853 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5854 // MWA: or from options or hotkey screens
5855 // JH: or if the command brief state already did this
5856 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5857 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5858 if ( !game_start_mission() ) // this should put us into a new state on failure!
5863 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5864 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5865 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5867 cmd_brief_init(team_num);
5873 case GS_STATE_SHIP_SELECT:
5877 case GS_STATE_WEAPON_SELECT:
5878 weapon_select_init();
5881 case GS_STATE_TEAM_SELECT:
5885 case GS_STATE_GAME_PAUSED:
5890 case GS_STATE_DEBUG_PAUSED:
5891 // game_stop_time();
5892 // os_set_title("FreeSpace - PAUSED");
5895 case GS_STATE_TRAINING_PAUSED:
5902 case GS_STATE_OPTIONS_MENU:
5904 options_menu_init();
5907 case GS_STATE_GAME_PLAY:
5908 // coming from the gameplay state or the main menu, we might need to load the mission
5909 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5910 if ( !game_start_mission() ) // this should put us into a new state.
5915 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5916 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5917 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5918 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5919 (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) ) {
5920 // JAS: Used to do all paging here.
5924 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5928 main_hall_stop_music();
5929 main_hall_stop_ambient();
5930 event_music_first_pattern(); // start the first pattern
5933 // special code that restores player ship selection and weapons loadout when doing a quick start
5934 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5935 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5936 wss_direct_restore_loadout();
5940 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5941 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5942 event_music_first_pattern(); // start the first pattern
5945 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5946 event_music_first_pattern(); // start the first pattern
5948 player_restore_target_and_weapon_link_prefs();
5950 Game_mode |= GM_IN_MISSION;
5953 // required to truely make mouse deltas zeroed in debug mouse code
5954 void mouse_force_pos(int x, int y);
5955 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5960 // only start time if in single player, or coming from multi wait state
5963 (Game_mode & GM_NORMAL) &&
5964 (old_state != GS_STATE_VIEW_CUTSCENES)
5966 (Game_mode & GM_MULTIPLAYER) && (
5967 (old_state == GS_STATE_MULTI_PAUSED) ||
5968 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5974 // when coming from the multi paused state, reset the timestamps
5975 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5976 multi_reset_timestamps();
5979 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5980 // initialize all object update details
5981 multi_oo_gameplay_init();
5984 // under certain circumstances, the server should reset the object update rate limiting stuff
5985 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5986 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5988 // reinitialize the rate limiting system for all clients
5989 multi_oo_rate_init_all();
5992 // multiplayer clients should always re-initialize their control info rate limiting system
5993 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5994 multi_oo_rate_init_all();
5998 if(Game_mode & GM_MULTIPLAYER){
5999 multi_ping_reset_players();
6002 Game_subspace_effect = 0;
6003 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6004 Game_subspace_effect = 1;
6005 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6006 game_start_subspace_ambient_sound();
6010 sound_env_set(&Game_sound_env);
6011 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6013 // clear multiplayer button info i
6014 extern button_info Multi_ship_status_bi;
6015 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6018 case GS_STATE_HUD_CONFIG:
6022 case GS_STATE_MULTI_JOIN_GAME:
6023 multi_join_clear_game_list();
6025 if (old_state != GS_STATE_OPTIONS_MENU) {
6026 multi_join_game_init();
6031 case GS_STATE_MULTI_HOST_SETUP:
6032 // don't reinitialize if we're coming back from the host options screen
6033 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6034 multi_create_game_init();
6039 case GS_STATE_MULTI_CLIENT_SETUP:
6040 if (old_state != GS_STATE_OPTIONS_MENU) {
6041 multi_game_client_setup_init();
6046 case GS_STATE_CONTROL_CONFIG:
6047 control_config_init();
6050 case GS_STATE_TECH_MENU:
6054 case GS_STATE_BARRACKS_MENU:
6055 if(old_state != GS_STATE_VIEW_MEDALS){
6060 case GS_STATE_MISSION_LOG_SCROLLBACK:
6061 hud_scrollback_init();
6064 case GS_STATE_DEATH_DIED:
6065 Player_died_time = timestamp(10);
6067 if(!(Game_mode & GM_MULTIPLAYER)){
6068 player_show_death_message();
6070 Game_mode |= GM_DEAD_DIED;
6073 case GS_STATE_DEATH_BLEW_UP:
6074 if ( !popupdead_is_active() ) {
6075 Player_ai->target_objnum = -1;
6078 // stop any local EMP effect
6081 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6082 Game_mode |= GM_DEAD_BLEW_UP;
6083 Show_viewing_from_self = 0;
6085 // timestamp how long we should wait before displaying the died popup
6086 if ( !popupdead_is_active() ) {
6087 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6091 case GS_STATE_GAMEPLAY_HELP:
6092 gameplay_help_init();
6095 case GS_STATE_CREDITS:
6096 main_hall_stop_music();
6097 main_hall_stop_ambient();
6101 case GS_STATE_VIEW_MEDALS:
6102 medal_main_init(Player);
6105 case GS_STATE_SHOW_GOALS:
6106 mission_show_goals_init();
6109 case GS_STATE_HOTKEY_SCREEN:
6110 mission_hotkey_init();
6113 case GS_STATE_MULTI_MISSION_SYNC:
6114 // if we're coming from the options screen, don't do any
6115 if(old_state == GS_STATE_OPTIONS_MENU){
6119 switch(Multi_sync_mode){
6120 case MULTI_SYNC_PRE_BRIEFING:
6121 // if moving from game forming to the team select state
6124 case MULTI_SYNC_POST_BRIEFING:
6125 // if moving from briefing into the mission itself
6128 // tell everyone that we're now loading data
6129 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6130 send_netplayer_update_packet();
6132 // JAS: Used to do all paging here!!!!
6134 Net_player->state = NETPLAYER_STATE_WAITING;
6135 send_netplayer_update_packet();
6137 Game_time_compression = F1_0;
6139 case MULTI_SYNC_INGAME:
6145 case GS_STATE_VIEW_CUTSCENES:
6146 cutscenes_screen_init();
6149 case GS_STATE_MULTI_STD_WAIT:
6150 multi_standalone_wait_init();
6153 case GS_STATE_STANDALONE_MAIN:
6154 // don't initialize if we're coming from one of these 2 states unless there are no
6155 // players left (reset situation)
6156 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6157 standalone_main_init();
6161 case GS_STATE_MULTI_PAUSED:
6165 case GS_STATE_INGAME_PRE_JOIN:
6166 multi_ingame_select_init();
6169 case GS_STATE_STANDALONE_POSTGAME:
6170 multi_standalone_postgame_init();
6173 case GS_STATE_INITIAL_PLAYER_SELECT:
6174 player_select_init();
6177 case GS_STATE_MULTI_START_GAME:
6178 multi_start_game_init();
6181 case GS_STATE_MULTI_HOST_OPTIONS:
6182 multi_host_options_init();
6185 case GS_STATE_END_OF_CAMPAIGN:
6186 mission_campaign_end_init();
6189 case GS_STATE_LOOP_BRIEF:
6196 // do stuff that may need to be done regardless of state
6197 void game_do_state_common(int state,int no_networking)
6199 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6200 snd_do_frame(); // update sound system
6201 event_music_do_frame(); // music needs to play across many states
6203 multi_log_process();
6205 if (no_networking) {
6209 // maybe do a multiplayer frame based on game mode and state type
6210 if (Game_mode & GM_MULTIPLAYER) {
6212 case GS_STATE_OPTIONS_MENU:
6213 case GS_STATE_GAMEPLAY_HELP:
6214 case GS_STATE_HOTKEY_SCREEN:
6215 case GS_STATE_HUD_CONFIG:
6216 case GS_STATE_CONTROL_CONFIG:
6217 case GS_STATE_MISSION_LOG_SCROLLBACK:
6218 case GS_STATE_SHOW_GOALS:
6219 case GS_STATE_VIEW_CUTSCENES:
6220 case GS_STATE_EVENT_DEBUG:
6221 multi_maybe_do_frame();
6225 game_do_networking();
6229 // Called once a frame.
6230 // You should never try to change the state
6231 // in here... if you think you need to, you probably really
6232 // need to post an event, not change the state.
6233 int Game_do_state_should_skip = 0;
6234 void game_do_state(int state)
6236 // always lets the do_state_common() function determine if the state should be skipped
6237 Game_do_state_should_skip = 0;
6239 // legal to set the should skip state anywhere in this function
6240 game_do_state_common(state); // do stuff that may need to be done regardless of state
6242 if(Game_do_state_should_skip){
6247 case GS_STATE_MAIN_MENU:
6248 game_set_frametime(GS_STATE_MAIN_MENU);
6249 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6252 main_hall_do(flFrametime);
6256 case GS_STATE_OPTIONS_MENU:
6257 game_set_frametime(GS_STATE_OPTIONS_MENU);
6258 options_menu_do_frame(flFrametime);
6261 case GS_STATE_BARRACKS_MENU:
6262 game_set_frametime(GS_STATE_BARRACKS_MENU);
6263 barracks_do_frame(flFrametime);
6266 case GS_STATE_TRAINING_MENU:
6267 game_set_frametime(GS_STATE_TRAINING_MENU);
6268 training_menu_do_frame(flFrametime);
6271 case GS_STATE_TECH_MENU:
6272 game_set_frametime(GS_STATE_TECH_MENU);
6273 techroom_do_frame(flFrametime);
6276 case GS_STATE_GAMEPLAY_HELP:
6277 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6278 gameplay_help_do_frame(flFrametime);
6281 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6285 case GS_STATE_GAME_PAUSED:
6289 case GS_STATE_DEBUG_PAUSED:
6291 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6296 case GS_STATE_TRAINING_PAUSED:
6297 game_training_pause_do();
6300 case GS_STATE_LOAD_MISSION_MENU:
6301 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6302 mission_load_menu_do();
6305 case GS_STATE_BRIEFING:
6306 game_set_frametime(GS_STATE_BRIEFING);
6307 brief_do_frame(flFrametime);
6310 case GS_STATE_DEBRIEF:
6311 game_set_frametime(GS_STATE_DEBRIEF);
6312 debrief_do_frame(flFrametime);
6315 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6316 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6317 multi_df_debrief_do();
6320 case GS_STATE_SHIP_SELECT:
6321 game_set_frametime(GS_STATE_SHIP_SELECT);
6322 ship_select_do(flFrametime);
6325 case GS_STATE_WEAPON_SELECT:
6326 game_set_frametime(GS_STATE_WEAPON_SELECT);
6327 weapon_select_do(flFrametime);
6330 case GS_STATE_MISSION_LOG_SCROLLBACK:
6331 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6332 hud_scrollback_do_frame(flFrametime);
6335 case GS_STATE_HUD_CONFIG:
6336 game_set_frametime(GS_STATE_HUD_CONFIG);
6337 hud_config_do_frame(flFrametime);
6340 case GS_STATE_MULTI_JOIN_GAME:
6341 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6342 multi_join_game_do_frame();
6345 case GS_STATE_MULTI_HOST_SETUP:
6346 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6347 multi_create_game_do();
6350 case GS_STATE_MULTI_CLIENT_SETUP:
6351 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6352 multi_game_client_setup_do_frame();
6355 case GS_STATE_CONTROL_CONFIG:
6356 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6357 control_config_do_frame(flFrametime);
6360 case GS_STATE_DEATH_DIED:
6364 case GS_STATE_DEATH_BLEW_UP:
6368 case GS_STATE_SIMULATOR_ROOM:
6369 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6370 sim_room_do_frame(flFrametime);
6373 case GS_STATE_CAMPAIGN_ROOM:
6374 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6375 campaign_room_do_frame(flFrametime);
6378 case GS_STATE_RED_ALERT:
6379 game_set_frametime(GS_STATE_RED_ALERT);
6380 red_alert_do_frame(flFrametime);
6383 case GS_STATE_CMD_BRIEF:
6384 game_set_frametime(GS_STATE_CMD_BRIEF);
6385 cmd_brief_do_frame(flFrametime);
6388 case GS_STATE_CREDITS:
6389 game_set_frametime(GS_STATE_CREDITS);
6390 credits_do_frame(flFrametime);
6393 case GS_STATE_VIEW_MEDALS:
6394 game_set_frametime(GS_STATE_VIEW_MEDALS);
6398 case GS_STATE_SHOW_GOALS:
6399 game_set_frametime(GS_STATE_SHOW_GOALS);
6400 mission_show_goals_do_frame(flFrametime);
6403 case GS_STATE_HOTKEY_SCREEN:
6404 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6405 mission_hotkey_do_frame(flFrametime);
6408 case GS_STATE_VIEW_CUTSCENES:
6409 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6410 cutscenes_screen_do_frame();
6413 case GS_STATE_MULTI_STD_WAIT:
6414 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6415 multi_standalone_wait_do();
6418 case GS_STATE_STANDALONE_MAIN:
6419 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6420 standalone_main_do();
6423 case GS_STATE_MULTI_PAUSED:
6424 game_set_frametime(GS_STATE_MULTI_PAUSED);
6428 case GS_STATE_TEAM_SELECT:
6429 game_set_frametime(GS_STATE_TEAM_SELECT);
6433 case GS_STATE_INGAME_PRE_JOIN:
6434 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6435 multi_ingame_select_do();
6438 case GS_STATE_EVENT_DEBUG:
6440 game_set_frametime(GS_STATE_EVENT_DEBUG);
6441 game_show_event_debug(flFrametime);
6445 case GS_STATE_STANDALONE_POSTGAME:
6446 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6447 multi_standalone_postgame_do();
6450 case GS_STATE_INITIAL_PLAYER_SELECT:
6451 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6455 case GS_STATE_MULTI_MISSION_SYNC:
6456 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6460 case GS_STATE_MULTI_START_GAME:
6461 game_set_frametime(GS_STATE_MULTI_START_GAME);
6462 multi_start_game_do();
6465 case GS_STATE_MULTI_HOST_OPTIONS:
6466 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6467 multi_host_options_do();
6470 case GS_STATE_END_OF_CAMPAIGN:
6471 mission_campaign_end_do();
6474 case GS_STATE_END_DEMO:
6475 game_set_frametime(GS_STATE_END_DEMO);
6476 end_demo_campaign_do();
6479 case GS_STATE_LOOP_BRIEF:
6480 game_set_frametime(GS_STATE_LOOP_BRIEF);
6484 } // end switch(gs_current_state)
6488 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6489 int game_do_ram_check(int ram_in_bytes)
6491 if ( ram_in_bytes < 30*1024*1024 ) {
6492 int allowed_to_run = 1;
6493 if ( ram_in_bytes < 25*1024*1024 ) {
6498 int Freespace_total_ram_MB;
6499 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6501 if ( allowed_to_run ) {
6503 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);
6508 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6509 if ( msgbox_rval == IDCANCEL ) {
6516 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);
6518 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6529 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6530 // If so, copy it over and remove the update directory.
6531 void game_maybe_update_launcher(char *exe_dir)
6534 char src_filename[MAX_PATH];
6535 char dest_filename[MAX_PATH];
6537 strcpy(src_filename, exe_dir);
6538 strcat(src_filename, NOX("\\update\\freespace.exe"));
6540 strcpy(dest_filename, exe_dir);
6541 strcat(dest_filename, NOX("\\freespace.exe"));
6543 // see if src_filename exists
6545 fp = fopen(src_filename, "rb");
6551 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6553 // copy updated freespace.exe to freespace exe dir
6554 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6555 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 );
6559 // delete the file in the update directory
6560 DeleteFile(src_filename);
6562 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6563 char update_dir[MAX_PATH];
6564 strcpy(update_dir, exe_dir);
6565 strcat(update_dir, NOX("\\update"));
6566 RemoveDirectory(update_dir);
6572 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6576 int sub_total_destroyed = 0;
6580 // get the total for all his children
6581 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6582 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6585 // find the # of faces for this _individual_ object
6586 total = submodel_get_num_polys(model_num, sm);
6587 if(strstr(pm->submodel[sm].name, "-destroyed")){
6588 sub_total_destroyed = total;
6592 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6595 *out_total += total + sub_total;
6596 *out_destroyed_total += sub_total_destroyed;
6599 #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);
6600 void game_spew_pof_info()
6602 char *pof_list[1000];
6605 int idx, model_num, i, j;
6607 int total, root_total, model_total, destroyed_total, counted;
6611 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6613 // spew info on all the pofs
6619 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6624 for(idx=0; idx<num_files; idx++, counted++){
6625 sprintf(str, "%s.pof", pof_list[idx]);
6626 model_num = model_load(str, 0, NULL);
6628 pm = model_get(model_num);
6630 // if we have a real model
6635 // go through and print all raw submodels
6636 cfputs("RAW\n", out);
6639 for (i=0; i<pm->n_models; i++) {
6640 total = submodel_get_num_polys(model_num, i);
6642 model_total += total;
6643 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6646 sprintf(str, "Model total %d\n", model_total);
6649 // now go through and do it by LOD
6650 cfputs("BY LOD\n\n", out);
6651 for(i=0; i<pm->n_detail_levels; i++){
6652 sprintf(str, "LOD %d\n", i);
6656 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6658 destroyed_total = 0;
6659 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6660 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6663 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6666 sprintf(str, "TOTAL: %d\n", total + root_total);
6668 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6670 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6673 cfputs("------------------------------------------------------------------------\n\n", out);
6677 if(counted >= MAX_POLYGON_MODELS - 5){
6690 game_spew_pof_info();
6693 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6698 // Don't let more than one instance of Freespace run.
6699 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6701 SetForegroundWindow(hwnd);
6706 // Find out how much RAM is on this machine
6709 ms.dwLength = sizeof(MEMORYSTATUS);
6710 GlobalMemoryStatus(&ms);
6711 Freespace_total_ram = ms.dwTotalPhys;
6713 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6717 if ( ms.dwTotalVirtual < 1024 ) {
6718 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6722 if (!vm_init(24*1024*1024)) {
6723 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 );
6727 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6729 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);
6737 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6738 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6739 seem worth bothering with.
6743 lResult = RegOpenKeyEx(
6744 HKEY_LOCAL_MACHINE, // Where it is
6745 "Software\\Microsoft\\DirectX", // name of key
6746 NULL, // DWORD reserved
6747 KEY_QUERY_VALUE, // Allows all changes
6748 &hKey // Location to store key
6751 if (lResult == ERROR_SUCCESS) {
6753 DWORD dwType, dwLen;
6756 lResult = RegQueryValueEx(
6757 hKey, // Handle to key
6758 "Version", // The values name
6759 NULL, // DWORD reserved
6760 &dwType, // What kind it is
6761 (ubyte *) version, // value to set
6762 &dwLen // How many bytes to set
6765 if (lResult == ERROR_SUCCESS) {
6766 dx_version = atoi(strstr(version, ".") + 1);
6770 DWORD dwType, dwLen;
6773 lResult = RegQueryValueEx(
6774 hKey, // Handle to key
6775 "InstalledVersion", // The values name
6776 NULL, // DWORD reserved
6777 &dwType, // What kind it is
6778 (ubyte *) &val, // value to set
6779 &dwLen // How many bytes to set
6782 if (lResult == ERROR_SUCCESS) {
6790 if (dx_version < 3) {
6791 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6792 "latest version of DirectX at:\n\n"
6793 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6795 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6796 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6801 //=====================================================
6802 // Make sure we're running in the right directory.
6806 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6807 char *p = exe_dir + strlen(exe_dir);
6809 // chop off the filename
6810 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6816 if ( strlen(exe_dir) > 0 ) {
6817 SetCurrentDirectory(exe_dir);
6820 // check for updated freespace.exe
6821 game_maybe_update_launcher(exe_dir);
6829 extern void windebug_memwatch_init();
6830 windebug_memwatch_init();
6834 parse_cmdline(szCmdLine);
6836 #ifdef STANDALONE_ONLY_BUILD
6838 nprintf(("Network", "Standalone running"));
6841 nprintf(("Network", "Standalone running"));
6849 // maybe spew pof stuff
6850 if(Cmdline_spew_pof_info){
6851 game_spew_pof_info();
6856 // non-demo, non-standalone, play the intro movie
6861 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) ){
6863 #if defined(OEM_BUILD)
6864 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6866 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6867 #endif // defined(OEM_BUILD)
6872 if ( !Is_standalone ) {
6874 // release -- movies always play
6877 // 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
6879 // movie_play( NOX("intro.mve"), 0 );
6881 // debug version, movie will only play with -showmovies
6882 #elif !defined(NDEBUG)
6885 // movie_play( NOX("intro.mve"), 0);
6888 if ( Cmdline_show_movies )
6889 movie_play( NOX("intro.mve"), 0 );
6898 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6900 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6904 // only important for non THREADED mode
6907 state = gameseq_process_events();
6908 if ( state == GS_STATE_QUIT_GAME ){
6915 demo_upsell_show_screens();
6917 #elif defined(OEM_BUILD)
6918 // show upsell screens on exit
6919 oem_upsell_show_screens();
6926 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6932 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6934 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6936 // Do nothing here - RecordExceptionInfo() has already done
6937 // everything that is needed. Actually this code won't even
6938 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6939 // the __except clause.
6943 nprintf(("WinMain", "exceptions shall fall through"));
6945 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6951 // launcher the fslauncher program on exit
6952 void game_launch_launcher_on_exit()
6956 PROCESS_INFORMATION pi;
6957 char cmd_line[2048];
6958 char original_path[1024] = "";
6960 memset( &si, 0, sizeof(STARTUPINFO) );
6964 _getcwd(original_path, 1023);
6966 // set up command line
6967 strcpy(cmd_line, original_path);
6968 strcat(cmd_line, "\\");
6969 strcat(cmd_line, LAUNCHER_FNAME);
6970 strcat(cmd_line, " -straight_to_update");
6972 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6973 cmd_line, // pointer to command line string
6974 NULL, // pointer to process security attributes
6975 NULL, // pointer to thread security attributes
6976 FALSE, // handle inheritance flag
6977 CREATE_DEFAULT_ERROR_MODE, // creation flags
6978 NULL, // pointer to new environment block
6979 NULL, // pointer to current directory name
6980 &si, // pointer to STARTUPINFO
6981 &pi // pointer to PROCESS_INFORMATION
6983 // to eliminate build warnings
6993 // This function is called when FreeSpace terminates normally.
6995 void game_shutdown(void)
7001 // don't ever flip a page on the standalone!
7002 if(!(Game_mode & GM_STANDALONE_SERVER)){
7008 // if the player has left the "player select" screen and quit the game without actually choosing
7009 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7010 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7014 // load up common multiplayer icons
7015 multi_unload_common_icons();
7017 shockwave_close(); // release any memory used by shockwave system
7018 fireball_close(); // free fireball system
7019 ship_close(); // free any memory that was allocated for the ships
7020 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7021 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7022 bm_unload_all(); // free bitmaps
7023 mission_campaign_close(); // close out the campaign stuff
7024 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7026 #ifdef MULTI_USE_LAG
7030 // the menu close functions will unload the bitmaps if they were displayed during the game
7031 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7034 training_menu_close();
7037 extern void joy_close();
7040 audiostream_close();
7042 event_music_close();
7046 // HACKITY HACK HACK
7047 // if this flag is set, we should be firing up the launcher when exiting freespace
7048 extern int Multi_update_fireup_launcher_on_exit;
7049 if(Multi_update_fireup_launcher_on_exit){
7050 game_launch_launcher_on_exit();
7054 // game_stop_looped_sounds()
7056 // This function will call the appropriate stop looped sound functions for those
7057 // modules which use looping sounds. It is not enough just to stop a looping sound
7058 // at the DirectSound level, the game is keeping track of looping sounds, and this
7059 // function is used to inform the game that looping sounds are being halted.
7061 void game_stop_looped_sounds()
7063 hud_stop_looped_locking_sounds();
7064 hud_stop_looped_engine_sounds();
7065 afterburner_stop_sounds();
7066 player_stop_looped_sounds();
7067 obj_snd_stop_all(); // stop all object-linked persistant sounds
7068 game_stop_subspace_ambient_sound();
7069 snd_stop(Radar_static_looping);
7070 Radar_static_looping = -1;
7071 snd_stop(Target_static_looping);
7072 shipfx_stop_engine_wash_sound();
7073 Target_static_looping = -1;
7076 //////////////////////////////////////////////////////////////////////////
7078 // Code for supporting an animating mouse pointer
7081 //////////////////////////////////////////////////////////////////////////
7083 typedef struct animating_obj
7092 static animating_obj Animating_mouse;
7094 // ----------------------------------------------------------------------------
7095 // init_animating_pointer()
7097 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7098 // gets properly initialized
7100 void init_animating_pointer()
7102 Animating_mouse.first_frame = -1;
7103 Animating_mouse.num_frames = 0;
7104 Animating_mouse.current_frame = -1;
7105 Animating_mouse.time = 0.0f;
7106 Animating_mouse.elapsed_time = 0.0f;
7109 // ----------------------------------------------------------------------------
7110 // load_animating_pointer()
7112 // Called at game init to load in the frames for the animating mouse pointer
7114 // input: filename => filename of animation file that holds the animation
7116 void load_animating_pointer(char *filename, int dx, int dy)
7121 init_animating_pointer();
7123 am = &Animating_mouse;
7124 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7125 if ( am->first_frame == -1 )
7126 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7127 am->current_frame = 0;
7128 am->time = am->num_frames / i2fl(fps);
7131 // ----------------------------------------------------------------------------
7132 // unload_animating_pointer()
7134 // Called at game shutdown to free the memory used to store the animation frames
7136 void unload_animating_pointer()
7141 am = &Animating_mouse;
7142 for ( i = 0; i < am->num_frames; i++ ) {
7143 Assert( (am->first_frame+i) >= 0 );
7144 bm_release(am->first_frame + i);
7147 am->first_frame = -1;
7149 am->current_frame = -1;
7152 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7153 void game_render_mouse(float frametime)
7158 // if animating cursor exists, play the next frame
7159 am = &Animating_mouse;
7160 if ( am->first_frame != -1 ) {
7161 mouse_get_pos(&mx, &my);
7162 am->elapsed_time += frametime;
7163 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7164 if ( am->current_frame >= am->num_frames ) {
7165 am->current_frame = 0;
7166 am->elapsed_time = 0.0f;
7168 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7172 // ----------------------------------------------------------------------------
7173 // game_maybe_draw_mouse()
7175 // determines whether to draw the mouse pointer at all, and what frame of
7176 // animation to use if the mouse is animating
7178 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7180 // input: frametime => elapsed frame time in seconds since last call
7182 void game_maybe_draw_mouse(float frametime)
7186 game_state = gameseq_get_state();
7188 switch ( game_state ) {
7189 case GS_STATE_GAME_PAUSED:
7190 // case GS_STATE_MULTI_PAUSED:
7191 case GS_STATE_GAME_PLAY:
7192 case GS_STATE_DEATH_DIED:
7193 case GS_STATE_DEATH_BLEW_UP:
7194 if ( popup_active() || popupdead_is_active() ) {
7206 if ( !Mouse_hidden )
7207 game_render_mouse(frametime);
7211 void game_do_training_checks()
7215 waypoint_list *wplp;
7217 if (Training_context & TRAINING_CONTEXT_SPEED) {
7218 s = (int) Player_obj->phys_info.fspeed;
7219 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7220 if (!Training_context_speed_set) {
7221 Training_context_speed_set = 1;
7222 Training_context_speed_timestamp = timestamp();
7226 Training_context_speed_set = 0;
7229 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7230 wplp = &Waypoint_lists[Training_context_path];
7231 if (wplp->count > Training_context_goal_waypoint) {
7232 i = Training_context_goal_waypoint;
7234 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7235 if (d <= Training_context_distance) {
7236 Training_context_at_waypoint = i;
7237 if (Training_context_goal_waypoint == i) {
7238 Training_context_goal_waypoint++;
7239 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7246 if (i == wplp->count)
7249 } while (i != Training_context_goal_waypoint);
7253 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7254 Players_target = Player_ai->target_objnum;
7255 Players_targeted_subsys = Player_ai->targeted_subsys;
7256 Players_target_timestamp = timestamp();
7260 /////////// Following is for event debug view screen
7264 #define EVENT_DEBUG_MAX 5000
7265 #define EVENT_DEBUG_EVENT 0x8000
7267 int Event_debug_index[EVENT_DEBUG_MAX];
7270 void game_add_event_debug_index(int n, int indent)
7272 if (ED_count < EVENT_DEBUG_MAX)
7273 Event_debug_index[ED_count++] = n | (indent << 16);
7276 void game_add_event_debug_sexp(int n, int indent)
7281 if (Sexp_nodes[n].first >= 0) {
7282 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7283 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7287 game_add_event_debug_index(n, indent);
7288 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7289 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7291 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7294 void game_event_debug_init()
7299 for (e=0; e<Num_mission_events; e++) {
7300 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7301 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7305 void game_show_event_debug(float frametime)
7309 int font_height, font_width;
7311 static int scroll_offset = 0;
7313 k = game_check_key();
7319 if (scroll_offset < 0)
7329 scroll_offset -= 20;
7330 if (scroll_offset < 0)
7335 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7339 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7345 gr_set_color_fast(&Color_bright);
7347 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7349 gr_set_color_fast(&Color_normal);
7351 gr_get_string_size(&font_width, &font_height, NOX("test"));
7352 y_max = gr_screen.max_h - font_height - 5;
7356 while (k < ED_count) {
7357 if (y_index > y_max)
7360 z = Event_debug_index[k];
7361 if (z & EVENT_DEBUG_EVENT) {
7363 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7364 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7365 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7366 Mission_events[z].repeat_count, Mission_events[z].interval);
7374 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7375 switch (Sexp_nodes[z & 0x7fff].value) {
7377 strcat(buf, NOX(" (True)"));
7381 strcat(buf, NOX(" (False)"));
7384 case SEXP_KNOWN_TRUE:
7385 strcat(buf, NOX(" (Always true)"));
7388 case SEXP_KNOWN_FALSE:
7389 strcat(buf, NOX(" (Always false)"));
7392 case SEXP_CANT_EVAL:
7393 strcat(buf, NOX(" (Can't eval)"));
7397 case SEXP_NAN_FOREVER:
7398 strcat(buf, NOX(" (Not a number)"));
7403 gr_printf(10, y_index, buf);
7404 y_index += font_height;
7417 extern int Tmap_npixels;
7419 int Tmap_num_too_big = 0;
7420 int Num_models_needing_splitting = 0;
7422 void Time_model( int modelnum )
7424 // mprintf(( "Timing ship '%s'\n", si->name ));
7426 vector eye_pos, model_pos;
7427 matrix eye_orient, model_orient;
7429 polymodel *pm = model_get( modelnum );
7431 int l = strlen(pm->filename);
7433 if ( (l == '/') || (l=='\\') || (l==':')) {
7439 char *pof_file = &pm->filename[l];
7441 int model_needs_splitting = 0;
7443 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7445 for (i=0; i<pm->n_textures; i++ ) {
7446 char filename[1024];
7449 int bmp_num = pm->original_textures[i];
7450 if ( bmp_num > -1 ) {
7451 bm_get_palette(pm->original_textures[i], pal, filename );
7453 bm_get_info( pm->original_textures[i],&w, &h );
7456 if ( (w > 512) || (h > 512) ) {
7457 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7459 model_needs_splitting++;
7462 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7466 if ( model_needs_splitting ) {
7467 Num_models_needing_splitting++;
7469 eye_orient = model_orient = vmd_identity_matrix;
7470 eye_pos = model_pos = vmd_zero_vector;
7472 eye_pos.z = -pm->rad*2.0f;
7474 vector eye_to_model;
7476 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7477 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7479 fix t1 = timer_get_fixed_seconds();
7482 ta.p = ta.b = ta.h = 0.0f;
7487 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7489 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7491 modelstats_num_polys = modelstats_num_verts = 0;
7493 while( ta.h < PI2 ) {
7496 vm_angles_2_matrix(&m1, &ta );
7497 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7504 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7506 model_clear_instance( modelnum );
7507 model_set_detail_level(0); // use highest detail level
7508 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7516 int k = key_inkey();
7517 if ( k == KEY_ESC ) {
7522 fix t2 = timer_get_fixed_seconds();
7524 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7525 //bitmaps_used_this_frame /= framecount;
7527 modelstats_num_polys /= framecount;
7528 modelstats_num_verts /= framecount;
7530 Tmap_npixels /=framecount;
7533 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7534 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 );
7535 // 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 );
7541 int Time_models = 0;
7542 DCF_BOOL( time_models, Time_models );
7544 void Do_model_timings_test()
7548 if ( !Time_models ) return;
7550 mprintf(( "Timing models!\n" ));
7554 ubyte model_used[MAX_POLYGON_MODELS];
7555 int model_id[MAX_POLYGON_MODELS];
7556 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7561 for (i=0; i<Num_ship_types; i++ ) {
7562 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7564 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7565 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7568 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7569 if ( !Texture_fp ) return;
7571 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7572 if ( !Time_fp ) return;
7574 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7575 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7577 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7578 if ( model_used[i] ) {
7579 Time_model( model_id[i] );
7583 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7584 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7593 // Call this function when you want to inform the player that a feature is not
7594 // enabled in the DEMO version of FreSpace
7595 void game_feature_not_in_demo_popup()
7597 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7600 // format the specified time (fixed point) into a nice string
7601 void game_format_time(fix m_time,char *time_str)
7604 int hours,minutes,seconds;
7607 mtime = f2fl(m_time);
7609 // get the hours, minutes and seconds
7610 hours = (int)(mtime / 3600.0f);
7612 mtime -= (3600.0f * (float)hours);
7614 seconds = (int)mtime%60;
7615 minutes = (int)mtime/60;
7617 // print the hour if necessary
7619 sprintf(time_str,XSTR( "%d:", 201),hours);
7620 // if there are less than 10 minutes, print a leading 0
7622 strcpy(tmp,NOX("0"));
7623 strcat(time_str,tmp);
7627 // print the minutes
7629 sprintf(tmp,XSTR( "%d:", 201),minutes);
7630 strcat(time_str,tmp);
7632 sprintf(time_str,XSTR( "%d:", 201),minutes);
7635 // print the seconds
7637 strcpy(tmp,NOX("0"));
7638 strcat(time_str,tmp);
7640 sprintf(tmp,"%d",seconds);
7641 strcat(time_str,tmp);
7644 // Stuff version string in *str.
7645 void get_version_string(char *str)
7648 if ( FS_VERSION_BUILD == 0 ) {
7649 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7651 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7654 #if defined (FS2_DEMO)
7656 #elif defined (OEM_BUILD)
7657 strcat(str, " (OEM)");
7663 char myname[_MAX_PATH];
7664 int namelen, major, minor, build, waste;
7665 unsigned int buf_size;
7671 // Find my EXE file name
7672 hMod = GetModuleHandle(NULL);
7673 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7675 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7676 infop = (char *)malloc(version_size);
7677 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7679 // get the product version
7680 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7681 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7683 sprintf(str,"Dv%d.%02d",major, minor);
7685 sprintf(str,"v%d.%02d",major, minor);
7690 void get_version_string_short(char *str)
7692 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7695 // ----------------------------------------------------------------
7697 // OEM UPSELL SCREENS BEGIN
7699 // ----------------------------------------------------------------
7700 #if defined(OEM_BUILD)
7702 #define NUM_OEM_UPSELL_SCREENS 3
7703 #define OEM_UPSELL_SCREEN_DELAY 10000
7705 static int Oem_upsell_bitmaps_loaded = 0;
7706 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7707 static int Oem_upsell_screen_number = 0;
7708 static int Oem_upsell_show_next_bitmap_time;
7711 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7724 static int Oem_normal_cursor = -1;
7725 static int Oem_web_cursor = -1;
7726 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7727 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7729 void oem_upsell_next_screen()
7731 Oem_upsell_screen_number++;
7732 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7733 // extra long delay, mouse shown on last upsell
7734 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7738 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7742 void oem_upsell_load_bitmaps()
7746 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7747 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7751 void oem_upsell_unload_bitmaps()
7755 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7756 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7757 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7762 Oem_upsell_bitmaps_loaded = 0;
7765 // clickable hotspot on 3rd OEM upsell screen
7766 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7768 28, 350, 287, 96 // x, y, w, h
7771 45, 561, 460, 152 // x, y, w, h
7775 void oem_upsell_show_screens()
7777 int current_time, k;
7780 if ( !Oem_upsell_bitmaps_loaded ) {
7781 oem_upsell_load_bitmaps();
7782 Oem_upsell_bitmaps_loaded = 1;
7785 // may use upsell screens more than once
7786 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7787 Oem_upsell_screen_number = 0;
7793 int nframes; // used to pass, not really needed (should be 1)
7794 Oem_normal_cursor = gr_get_cursor_bitmap();
7795 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7796 Assert(Oem_web_cursor >= 0);
7797 if (Oem_web_cursor < 0) {
7798 Oem_web_cursor = Oem_normal_cursor;
7803 //oem_reset_trailer_timer();
7805 current_time = timer_get_milliseconds();
7810 // advance screen on keypress or timeout
7811 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7812 oem_upsell_next_screen();
7815 // check if we are done
7816 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7817 Oem_upsell_screen_number--;
7820 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7825 // show me the upsell
7826 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7827 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7831 // if this is the 3rd upsell, make it clickable, d00d
7832 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7834 int button_state = mouse_get_pos(&mx, &my);
7835 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])
7836 && (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]) )
7839 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7842 if (button_state & MOUSE_LEFT_BUTTON) {
7844 multi_pxo_url(OEM_UPSELL_URL);
7848 // switch cursor back to normal one
7849 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7854 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7864 oem_upsell_unload_bitmaps();
7866 // switch cursor back to normal one
7867 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7871 #endif // defined(OEM_BUILD)
7872 // ----------------------------------------------------------------
7874 // OEM UPSELL SCREENS END
7876 // ----------------------------------------------------------------
7880 // ----------------------------------------------------------------
7882 // DEMO UPSELL SCREENS BEGIN
7884 // ----------------------------------------------------------------
7888 //#define NUM_DEMO_UPSELL_SCREENS 4
7890 #define NUM_DEMO_UPSELL_SCREENS 2
7891 #define DEMO_UPSELL_SCREEN_DELAY 3000
7893 static int Demo_upsell_bitmaps_loaded = 0;
7894 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7895 static int Demo_upsell_screen_number = 0;
7896 static int Demo_upsell_show_next_bitmap_time;
7899 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7912 void demo_upsell_next_screen()
7914 Demo_upsell_screen_number++;
7915 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7916 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7918 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7922 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7923 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7924 #ifndef HARDWARE_ONLY
7925 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7932 void demo_upsell_load_bitmaps()
7936 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7937 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7941 void demo_upsell_unload_bitmaps()
7945 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7946 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7947 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7952 Demo_upsell_bitmaps_loaded = 0;
7955 void demo_upsell_show_screens()
7957 int current_time, k;
7960 if ( !Demo_upsell_bitmaps_loaded ) {
7961 demo_upsell_load_bitmaps();
7962 Demo_upsell_bitmaps_loaded = 1;
7965 // may use upsell screens more than once
7966 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7967 Demo_upsell_screen_number = 0;
7974 demo_reset_trailer_timer();
7976 current_time = timer_get_milliseconds();
7983 // don't time out, wait for keypress
7985 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7986 demo_upsell_next_screen();
7991 demo_upsell_next_screen();
7994 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7995 Demo_upsell_screen_number--;
7998 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8003 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8004 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8009 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8019 demo_upsell_unload_bitmaps();
8024 // ----------------------------------------------------------------
8026 // DEMO UPSELL SCREENS END
8028 // ----------------------------------------------------------------
8031 // ----------------------------------------------------------------
8033 // Subspace Ambient Sound START
8035 // ----------------------------------------------------------------
8037 static int Subspace_ambient_left_channel = -1;
8038 static int Subspace_ambient_right_channel = -1;
8041 void game_start_subspace_ambient_sound()
8043 if ( Subspace_ambient_left_channel < 0 ) {
8044 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8047 if ( Subspace_ambient_right_channel < 0 ) {
8048 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8052 void game_stop_subspace_ambient_sound()
8054 if ( Subspace_ambient_left_channel >= 0 ) {
8055 snd_stop(Subspace_ambient_left_channel);
8056 Subspace_ambient_left_channel = -1;
8059 if ( Subspace_ambient_right_channel >= 0 ) {
8060 snd_stop(Subspace_ambient_right_channel);
8061 Subspace_ambient_right_channel = -1;
8065 // ----------------------------------------------------------------
8067 // Subspace Ambient Sound END
8069 // ----------------------------------------------------------------
8071 // ----------------------------------------------------------------
8073 // CDROM detection code START
8075 // ----------------------------------------------------------------
8077 #define CD_SIZE_72_MINUTE_MAX (697000000)
8079 uint game_get_cd_used_space(char *path)
8083 char use_path[512] = "";
8084 char sub_path[512] = "";
8085 WIN32_FIND_DATA find;
8088 // recurse through all files and directories
8089 strcpy(use_path, path);
8090 strcat(use_path, "*.*");
8091 find_handle = FindFirstFile(use_path, &find);
8094 if(find_handle == INVALID_HANDLE_VALUE){
8100 // subdirectory. make sure to ignore . and ..
8101 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8103 strcpy(sub_path, path);
8104 strcat(sub_path, find.cFileName);
8105 strcat(sub_path, "\\");
8106 total += game_get_cd_used_space(sub_path);
8108 total += (uint)find.nFileSizeLow;
8110 } while(FindNextFile(find_handle, &find));
8113 FindClose(find_handle);
8125 // if volume_name is non-null, the CD name must match that
8126 int find_freespace_cd(char *volume_name)
8129 char oldpath[MAX_PATH];
8133 int volume_match = 0;
8137 GetCurrentDirectory(MAX_PATH, oldpath);
8139 for (i = 0; i < 26; i++)
8145 path[0] = (char)('A'+i);
8146 if (GetDriveType(path) == DRIVE_CDROM) {
8148 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8149 nprintf(("CD", "CD volume: %s\n", volume));
8151 // check for any CD volume
8152 int volume1_present = 0;
8153 int volume2_present = 0;
8154 int volume3_present = 0;
8156 char full_check[512] = "";
8158 // look for setup.exe
8159 strcpy(full_check, path);
8160 strcat(full_check, "setup.exe");
8161 find_handle = _findfirst(full_check, &find);
8162 if(find_handle != -1){
8163 volume1_present = 1;
8164 _findclose(find_handle);
8167 // look for intro.mve
8168 strcpy(full_check, path);
8169 strcat(full_check, "intro.mve");
8170 find_handle = _findfirst(full_check, &find);
8171 if(find_handle != -1){
8172 volume2_present = 1;
8173 _findclose(find_handle);
8176 // look for endpart1.mve
8177 strcpy(full_check, path);
8178 strcat(full_check, "endpart1.mve");
8179 find_handle = _findfirst(full_check, &find);
8180 if(find_handle != -1){
8181 volume3_present = 1;
8182 _findclose(find_handle);
8185 // see if we have the specific CD we're looking for
8186 if ( volume_name ) {
8188 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8192 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8196 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8200 if ( volume1_present || volume2_present || volume3_present ) {
8205 // 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
8206 if ( volume_match ){
8208 // 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
8209 if(volume2_present || volume3_present) {
8210 // first step - check to make sure its a cdrom
8211 if(GetDriveType(path) != DRIVE_CDROM){
8215 #if !defined(OEM_BUILD)
8216 // oem not on 80 min cds, so dont check tha size
8218 uint used_space = game_get_cd_used_space(path);
8219 if(used_space < CD_SIZE_72_MINUTE_MAX){
8222 #endif // !defined(OEM_BUILD)
8230 #endif // RELEASE_REAL
8236 SetCurrentDirectory(oldpath);
8245 int set_cdrom_path(int drive_num)
8249 if (drive_num < 0) { //no CD
8251 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8254 strcpy(Game_CDROM_dir,""); //set directory
8258 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8274 i = find_freespace_cd();
8276 rval = set_cdrom_path(i);
8280 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8282 nprintf(("CD", "FreeSpace CD not found\n"));
8290 int Last_cd_label_found = 0;
8291 char Last_cd_label[256];
8293 int game_cd_changed()
8300 if ( strlen(Game_CDROM_dir) == 0 ) {
8304 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8306 if ( found != Last_cd_label_found ) {
8307 Last_cd_label_found = found;
8309 mprintf(( "CD '%s' was inserted\n", label ));
8312 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8316 if ( Last_cd_label_found ) {
8317 if ( !stricmp( Last_cd_label, label )) {
8318 //mprintf(( "CD didn't change\n" ));
8320 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8324 // none found before, none found now.
8325 //mprintf(( "still no CD...\n" ));
8329 Last_cd_label_found = found;
8331 strcpy( Last_cd_label, label );
8333 strcpy( Last_cd_label, "" );
8344 // check if _any_ FreeSpace2 CDs are in the drive
8345 // return: 1 => CD now in drive
8346 // 0 => Could not find CD, they refuse to put it in the drive
8347 int game_do_cd_check(char *volume_name)
8349 #if !defined(GAME_CD_CHECK)
8355 int num_attempts = 0;
8356 int refresh_files = 0;
8358 int path_set_ok, popup_rval;
8360 cd_drive_num = find_freespace_cd(volume_name);
8361 path_set_ok = set_cdrom_path(cd_drive_num);
8362 if ( path_set_ok ) {
8364 if ( refresh_files ) {
8376 // no CD found, so prompt user
8377 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8379 if ( popup_rval != 1 ) {
8384 if ( num_attempts++ > 5 ) {
8395 // check if _any_ FreeSpace2 CDs are in the drive
8396 // return: 1 => CD now in drive
8397 // 0 => Could not find CD, they refuse to put it in the drive
8398 int game_do_cd_check_specific(char *volume_name, int cdnum)
8403 int num_attempts = 0;
8404 int refresh_files = 0;
8406 int path_set_ok, popup_rval;
8408 cd_drive_num = find_freespace_cd(volume_name);
8409 path_set_ok = set_cdrom_path(cd_drive_num);
8410 if ( path_set_ok ) {
8412 if ( refresh_files ) {
8423 // no CD found, so prompt user
8424 #if defined(DVD_MESSAGE_HACK)
8425 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8427 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8430 if ( popup_rval != 1 ) {
8435 if ( num_attempts++ > 5 ) {
8445 // only need to do this in RELEASE_REAL
8446 int game_do_cd_mission_check(char *filename)
8452 fs_builtin_mission *m = game_find_builtin_mission(filename);
8454 // check for changed CD
8455 if(game_cd_changed()){
8460 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8464 // not builtin, so do a general check (any FS2 CD will do)
8466 return game_do_cd_check();
8469 // does not have any CD requirement, do a general check
8470 if(strlen(m->cd_volume) <= 0){
8471 return game_do_cd_check();
8475 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8477 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8479 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8482 return game_do_cd_check();
8485 // did we find the cd?
8486 if(find_freespace_cd(m->cd_volume) >= 0){
8490 // make sure the volume exists
8491 int num_attempts = 0;
8492 int refresh_files = 0;
8494 int path_set_ok, popup_rval;
8496 cd_drive_num = find_freespace_cd(m->cd_volume);
8497 path_set_ok = set_cdrom_path(cd_drive_num);
8498 if ( path_set_ok ) {
8500 if ( refresh_files ) {
8507 // no CD found, so prompt user
8508 #if defined(DVD_MESSAGE_HACK)
8509 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8511 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8515 if ( popup_rval != 1 ) {
8520 if ( num_attempts++ > 5 ) {
8532 // ----------------------------------------------------------------
8534 // CDROM detection code END
8536 // ----------------------------------------------------------------
8538 // ----------------------------------------------------------------
8539 // SHIPS TBL VERIFICATION STUFF
8542 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8543 #define NUM_SHIPS_TBL_CHECKSUMS 1
8545 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8546 -463907578, // US - beta 1
8547 1696074201, // FS2 demo
8550 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8551 // -1022810006, // 1.0 FULL
8552 -1254285366 // 1.2 FULL (German)
8555 void verify_ships_tbl()
8559 Game_ships_tbl_valid = 1;
8565 // detect if the packfile exists
8566 CFILE *detect = cfopen("ships.tbl", "rb");
8567 Game_ships_tbl_valid = 0;
8571 Game_ships_tbl_valid = 0;
8575 // get the long checksum of the file
8577 cfseek(detect, 0, SEEK_SET);
8578 cf_chksum_long(detect, &file_checksum);
8582 // now compare the checksum/filesize against known #'s
8583 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8584 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8585 Game_ships_tbl_valid = 1;
8592 DCF(shipspew, "display the checksum for the current ships.tbl")
8595 CFILE *detect = cfopen("ships.tbl", "rb");
8596 // get the long checksum of the file
8598 cfseek(detect, 0, SEEK_SET);
8599 cf_chksum_long(detect, &file_checksum);
8602 dc_printf("%d", file_checksum);
8605 // ----------------------------------------------------------------
8606 // WEAPONS TBL VERIFICATION STUFF
8609 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8610 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8612 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8613 141718090, // US - beta 1
8614 -266420030, // demo 1
8617 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8618 // 399297860, // 1.0 FULL
8619 -553984927 // 1.2 FULL (german)
8622 void verify_weapons_tbl()
8626 Game_weapons_tbl_valid = 1;
8632 // detect if the packfile exists
8633 CFILE *detect = cfopen("weapons.tbl", "rb");
8634 Game_weapons_tbl_valid = 0;
8638 Game_weapons_tbl_valid = 0;
8642 // get the long checksum of the file
8644 cfseek(detect, 0, SEEK_SET);
8645 cf_chksum_long(detect, &file_checksum);
8649 // now compare the checksum/filesize against known #'s
8650 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8651 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8652 Game_weapons_tbl_valid = 1;
8659 DCF(wepspew, "display the checksum for the current weapons.tbl")
8662 CFILE *detect = cfopen("weapons.tbl", "rb");
8663 // get the long checksum of the file
8665 cfseek(detect, 0, SEEK_SET);
8666 cf_chksum_long(detect, &file_checksum);
8669 dc_printf("%d", file_checksum);
8672 // if the game is running using hacked data
8673 int game_hacked_data()
8676 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8684 void display_title_screen()
8686 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8687 ///int title_bitmap;
8690 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8691 if (title_bitmap == -1) {
8697 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8698 extern void d3d_start_frame();
8704 gr_set_bitmap(title_bitmap);
8711 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8712 extern void d3d_stop_frame();
8720 bm_unload(title_bitmap);
8721 #endif // FS2_DEMO || OEM_BUILD
8724 // return true if the game is running with "low memory", which is less than 48MB
8725 bool game_using_low_mem()
8727 if (Use_low_mem == 0) {