2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.11 2002/06/01 09:00:34 relnev
11 * silly debug memmanager
13 * Revision 1.10 2002/06/01 07:12:32 relnev
14 * a few NDEBUG updates.
16 * removed a few warnings.
18 * Revision 1.9 2002/05/31 03:05:59 relnev
21 * Revision 1.8 2002/05/29 02:52:32 theoddone33
22 * Enable OpenGL renderer
24 * Revision 1.7 2002/05/28 08:52:03 relnev
25 * implemented two assembly stubs.
27 * cleaned up a few warnings.
29 * added a little demo hackery to make it progress a little farther.
31 * Revision 1.6 2002/05/28 06:28:20 theoddone33
32 * Filesystem mods, actually reads some data files now
34 * Revision 1.5 2002/05/28 04:07:28 theoddone33
35 * New graphics stubbing arrangement
37 * Revision 1.4 2002/05/27 22:46:52 theoddone33
38 * Remove more undefined symbols
40 * Revision 1.3 2002/05/26 23:31:18 relnev
41 * added a few files that needed to be compiled
43 * freespace.cpp: now compiles
45 * Revision 1.2 2002/05/07 03:16:44 theoddone33
46 * The Great Newline Fix
48 * Revision 1.1.1.1 2002/05/03 03:28:09 root
52 * 201 6/16/00 3:15p Jefff
53 * sim of the year dvd version changes, a few german soty localization
56 * 200 11/03/99 11:06a Jefff
59 * 199 10/26/99 5:07p Jamest
60 * fixed jeffs dumb debug code
62 * 198 10/25/99 5:53p Jefff
63 * call control_config_common_init() on startup
65 * 197 10/14/99 10:18a Daveb
66 * Fixed incorrect CD checking problem on standalone server.
68 * 196 10/13/99 9:22a Daveb
69 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
70 * related to movies. Fixed launcher spawning from PXO screen.
72 * 195 10/06/99 11:05a Jefff
73 * new oem upsell 3 hotspot coords
75 * 194 10/06/99 10:31a Jefff
78 * 193 10/01/99 9:10a Daveb
81 * 192 9/15/99 4:57a Dave
82 * Updated ships.tbl checksum
84 * 191 9/15/99 3:58a Dave
85 * Removed framerate warning at all times.
87 * 190 9/15/99 3:16a Dave
88 * Remove mt-011.fs2 from the builtin mission list.
90 * 189 9/15/99 1:45a Dave
91 * Don't init joystick on standalone. Fixed campaign mode on standalone.
92 * Fixed no-score-report problem in TvT
94 * 188 9/14/99 6:08a Dave
95 * Updated (final) single, multi, and campaign list.
97 * 187 9/14/99 3:26a Dave
98 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
99 * respawn-too-early problem. Made a few crash points safe.
101 * 186 9/13/99 4:52p Dave
104 * 185 9/12/99 8:09p Dave
105 * Fixed problem where skip-training button would cause mission messages
106 * not to get paged out for the current mission.
108 * 184 9/10/99 11:53a Dave
109 * Shutdown graphics before sound to eliminate apparent lockups when
110 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
112 * 183 9/09/99 11:40p Dave
113 * Handle an Assert() in beam code. Added supernova sounds. Play the right
114 * 2 end movies properly, based upon what the player did in the mission.
116 * 182 9/08/99 10:29p Dave
117 * Make beam sound pausing and unpausing much safer.
119 * 181 9/08/99 10:01p Dave
120 * Make sure game won't run in a drive's root directory. Make sure
121 * standalone routes suqad war messages properly to the host.
123 * 180 9/08/99 3:22p Dave
124 * Updated builtin mission list.
126 * 179 9/08/99 12:01p Jefff
127 * fixed Game_builtin_mission_list typo on Training-2.fs2
129 * 178 9/08/99 9:48a Andsager
130 * Add force feedback for engine wash.
132 * 177 9/07/99 4:01p Dave
133 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
134 * does everything properly (setting up address when binding). Remove
135 * black rectangle background from UI_INPUTBOX.
137 * 176 9/13/99 2:40a Dave
138 * Comment in full 80 minute CD check for RELEASE_REAL builds.
140 * 175 9/06/99 6:38p Dave
141 * Improved CD detection code.
143 * 174 9/06/99 1:30a Dave
144 * Intermediate checkin. Started on enforcing CD-in-drive to play the
147 * 173 9/06/99 1:16a Dave
148 * Make sure the user sees the intro movie.
150 * 172 9/04/99 8:00p Dave
151 * Fixed up 1024 and 32 bit movie support.
153 * 171 9/03/99 1:32a Dave
154 * CD checking by act. Added support to play 2 cutscenes in a row
155 * seamlessly. Fixed super low level cfile bug related to files in the
156 * root directory of a CD. Added cheat code to set campaign mission # in
159 * 170 9/01/99 10:49p Dave
160 * Added nice SquadWar checkbox to the client join wait screen.
162 * 169 9/01/99 10:14a Dave
165 * 168 8/29/99 4:51p Dave
166 * Fixed damaged checkin.
168 * 167 8/29/99 4:18p Andsager
169 * New "burst" limit for friendly damage. Also credit more damage done
170 * against large friendly ships.
172 * 166 8/27/99 6:38p Alanl
173 * crush the blasted repeating messages bug
175 * 164 8/26/99 9:09p Dave
176 * Force framerate check in everything but a RELEASE_REAL build.
178 * 163 8/26/99 9:45a Dave
179 * First pass at easter eggs and cheats.
181 * 162 8/24/99 8:55p Dave
182 * Make sure nondimming pixels work properly in tech menu.
184 * 161 8/24/99 1:49a Dave
185 * Fixed client-side afterburner stuttering. Added checkbox for no version
186 * checking on PXO join. Made button info passing more friendly between
189 * 160 8/22/99 5:53p Dave
190 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
191 * instead of ship designations for multiplayer players.
193 * 159 8/22/99 1:19p Dave
194 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
195 * which d3d cards are detected.
197 * 158 8/20/99 2:09p Dave
198 * PXO banner cycling.
200 * 157 8/19/99 10:59a Dave
201 * Packet loss detection.
203 * 156 8/19/99 10:12a Alanl
204 * preload mission-specific messages on machines greater than 48MB
206 * 155 8/16/99 4:04p Dave
207 * Big honking checkin.
209 * 154 8/11/99 5:54p Dave
210 * Fixed collision problem. Fixed standalone ghost problem.
212 * 153 8/10/99 7:59p Jefff
215 * 152 8/10/99 6:54p Dave
216 * Mad optimizations. Added paging to the nebula effect.
218 * 151 8/10/99 3:44p Jefff
219 * loads Intelligence information on startup
221 * 150 8/09/99 3:47p Dave
222 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
223 * non-nebula missions.
225 * 149 8/09/99 2:21p Andsager
226 * Fix patching from multiplayer direct to launcher update tab.
228 * 148 8/09/99 10:36a Dave
229 * Version info for game.
231 * 147 8/06/99 9:46p Dave
232 * Hopefully final changes for the demo.
234 * 146 8/06/99 3:34p Andsager
235 * Make title version info "(D)" -> "D" show up nicely
237 * 145 8/06/99 2:59p Adamp
238 * Fixed NT launcher/update problem.
240 * 144 8/06/99 1:52p Dave
241 * Bumped up MAX_BITMAPS for the demo.
243 * 143 8/06/99 12:17p Andsager
244 * Demo: down to just 1 demo dog
246 * 142 8/05/99 9:39p Dave
247 * Yet another new checksum.
249 * 141 8/05/99 6:19p Dave
250 * New demo checksums.
252 * 140 8/05/99 5:31p Andsager
253 * Up demo version 1.01
255 * 139 8/05/99 4:22p Andsager
256 * No time limit on upsell screens. Reverse order of display of upsell
259 * 138 8/05/99 4:17p Dave
260 * Tweaks to client interpolation.
262 * 137 8/05/99 3:52p Danw
264 * 136 8/05/99 3:01p Danw
266 * 135 8/05/99 2:43a Anoop
267 * removed duplicate definition.
269 * 134 8/05/99 2:13a Dave
272 * 133 8/05/99 2:05a Dave
275 * 132 8/05/99 1:22a Andsager
278 * 131 8/04/99 9:51p Andsager
279 * Add title screen to demo
281 * 130 8/04/99 6:47p Jefff
282 * fixed link error resulting from #ifdefs
284 * 129 8/04/99 6:26p Dave
285 * Updated ship tbl checksum.
287 * 128 8/04/99 5:40p Andsager
288 * Add multiple demo dogs
290 * 127 8/04/99 5:36p Andsager
291 * Show upsell screens at end of demo campaign before returning to main
294 * 126 8/04/99 11:42a Danw
295 * tone down EAX reverb
297 * 125 8/04/99 11:23a Dave
298 * Updated demo checksums.
300 * 124 8/03/99 11:02p Dave
301 * Maybe fixed sync problems in multiplayer.
303 * 123 8/03/99 6:21p Jefff
306 * 122 8/03/99 3:44p Andsager
307 * Launch laucher if trying to run FS without first having configured
310 * 121 8/03/99 12:45p Dave
313 * 120 8/02/99 9:13p Dave
316 * 119 7/30/99 10:31p Dave
317 * Added comm menu to the configurable hud files.
319 * 118 7/30/99 5:17p Andsager
320 * first fs2demo checksums
322 * 117 7/29/99 3:09p Anoop
324 * 116 7/29/99 12:05a Dave
325 * Nebula speed optimizations.
327 * 115 7/27/99 8:59a Andsager
328 * Make major, minor version consistent for all builds. Only show major
329 * and minor for launcher update window.
331 * 114 7/26/99 5:50p Dave
332 * Revised ingame join. Better? We'll see....
334 * 113 7/26/99 5:27p Andsager
335 * Add training mission as builtin to demo build
337 * 112 7/24/99 1:54p Dave
338 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
341 * 111 7/22/99 4:00p Dave
342 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
344 * 110 7/21/99 8:10p Dave
345 * First run of supernova effect.
347 * 109 7/20/99 1:49p Dave
348 * Peter Drake build. Fixed some release build warnings.
350 * 108 7/19/99 2:26p Andsager
351 * set demo multiplayer missions
353 * 107 7/18/99 5:19p Dave
354 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
356 * 106 7/16/99 1:50p Dave
357 * 8 bit aabitmaps. yay.
359 * 105 7/15/99 3:07p Dave
360 * 32 bit detection support. Mouse coord commandline.
362 * 104 7/15/99 2:13p Dave
363 * Added 32 bit detection.
365 * 103 7/15/99 9:20a Andsager
366 * FS2_DEMO initial checkin
368 * 102 7/14/99 11:02a Dave
369 * Skill level default back to easy. Blech.
371 * 101 7/09/99 5:54p Dave
372 * Seperated cruiser types into individual types. Added tons of new
373 * briefing icons. Campaign screen.
375 * 100 7/08/99 4:43p Andsager
376 * New check for sparky_hi and print if not found.
378 * 99 7/08/99 10:53a Dave
379 * New multiplayer interpolation scheme. Not 100% done yet, but still
380 * better than the old way.
382 * 98 7/06/99 4:24p Dave
383 * Mid-level checkin. Starting on some potentially cool multiplayer
386 * 97 7/06/99 3:35p Andsager
387 * Allow movie to play before red alert mission.
389 * 96 7/03/99 5:50p Dave
390 * Make rotated bitmaps draw properly in padlock views.
392 * 95 7/02/99 9:55p Dave
393 * Player engine wash sound.
395 * 94 7/02/99 4:30p Dave
396 * Much more sophisticated lightning support.
398 * 93 6/29/99 7:52p Dave
399 * Put in exception handling in FS2.
401 * 92 6/22/99 9:37p Dave
402 * Put in pof spewing.
404 * 91 6/16/99 4:06p Dave
405 * New pilot info popup. Added new draw-bitmap-as-poly function.
407 * 90 6/15/99 1:56p Andsager
408 * For release builds, allow start up in high res only with
411 * 89 6/15/99 9:34a Dave
412 * Fixed key checking in single threaded version of the stamp notification
415 * 88 6/09/99 2:55p Andsager
416 * Allow multiple asteroid subtypes (of large, medium, small) and follow
419 * 87 6/08/99 1:14a Dave
420 * Multi colored hud test.
422 * 86 6/04/99 9:52a Dave
423 * Fixed some rendering problems.
425 * 85 6/03/99 10:15p Dave
426 * Put in temporary main hall screen.
428 * 84 6/02/99 6:18p Dave
429 * Fixed TNT lockup problems! Wheeeee!
431 * 83 6/01/99 3:52p Dave
432 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
433 * dead popup, pxo find player popup, pxo private room popup.
435 * 82 5/26/99 1:28p Jasenw
436 * changed coords for loading ani
438 * 81 5/26/99 11:46a Dave
439 * Added ship-blasting lighting and made the randomization of lighting
440 * much more customizable.
442 * 80 5/24/99 5:45p Dave
443 * Added detail levels to the nebula, with a decent speedup. Split nebula
444 * lightning into its own section.
462 #include "systemvars.h"
467 #include "starfield.h"
468 #include "lighting.h"
473 #include "fireballs.h"
477 #include "floating.h"
478 #include "gamesequence.h"
480 #include "optionsmenu.h"
481 #include "playermenu.h"
482 #include "trainingmenu.h"
483 #include "techmenu.h"
486 #include "hudmessage.h"
488 #include "missiongoals.h"
489 #include "missionparse.h"
494 #include "multiutil.h"
495 #include "multimsgs.h"
499 #include "freespace.h"
500 #include "managepilot.h"
502 #include "contexthelp.h"
505 #include "missionbrief.h"
506 #include "missiondebrief.h"
508 #include "missionshipchoice.h"
510 #include "hudconfig.h"
511 #include "controlsconfig.h"
512 #include "missionmessage.h"
513 #include "missiontraining.h"
515 #include "hudtarget.h"
519 #include "eventmusic.h"
520 #include "animplay.h"
521 #include "missionweaponchoice.h"
522 #include "missionlog.h"
523 #include "audiostr.h"
525 #include "missioncampaign.h"
527 #include "missionhotkey.h"
528 #include "objectsnd.h"
529 #include "cmeasure.h"
531 #include "linklist.h"
532 #include "shockwave.h"
533 #include "afterburner.h"
538 #include "stand_gui.h"
539 #include "pcxutils.h"
540 #include "hudtargetbox.h"
541 #include "multi_xfer.h"
542 #include "hudescort.h"
543 #include "multiutil.h"
546 #include "multiteamselect.h"
549 #include "readyroom.h"
550 #include "mainhallmenu.h"
551 #include "multilag.h"
553 #include "particle.h"
555 #include "multi_ingame.h"
556 #include "snazzyui.h"
557 #include "asteroid.h"
558 #include "popupdead.h"
559 #include "multi_voice.h"
560 #include "missioncmdbrief.h"
561 #include "redalert.h"
562 #include "gameplayhelp.h"
563 #include "multilag.h"
564 #include "staticrand.h"
565 #include "multi_pmsg.h"
566 #include "levelpaging.h"
567 #include "observer.h"
568 #include "multi_pause.h"
569 #include "multi_endgame.h"
570 #include "cutscenes.h"
571 #include "multi_respawn.h"
572 // #include "movie.h"
573 #include "multi_obj.h"
574 #include "multi_log.h"
576 #include "localize.h"
577 #include "osregistry.h"
578 #include "barracks.h"
579 #include "missionpause.h"
581 #include "alphacolors.h"
582 #include "objcollide.h"
585 #include "neblightning.h"
586 #include "shipcontrails.h"
589 #include "multi_dogfight.h"
590 #include "multi_rate.h"
591 #include "muzzleflash.h"
595 #include "mainhalltemp.h"
596 #include "exceptionhandler.h"
600 #include "supernova.h"
601 #include "hudshield.h"
602 // #include "names.h"
604 #include "missionloopbrief.h"
608 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
614 // 1.00.04 5/26/98 MWA -- going final (12 pm)
615 // 1.00.03 5/26/98 MWA -- going final (3 am)
616 // 1.00.02 5/25/98 MWA -- going final
617 // 1.00.01 5/25/98 MWA -- going final
618 // 0.90 5/21/98 MWA -- getting ready for final.
619 // 0.10 4/9/98. Set by MK.
621 // Demo version: (obsolete since DEMO codebase split from tree)
622 // 0.03 4/10/98 AL. Interplay rev
623 // 0.02 4/8/98 MK. Increased when this system was modified.
624 // 0.01 4/7/98? AL. First release to Interplay QA.
627 // 1.00 5/28/98 AL. First release to Interplay QA.
629 void game_level_init(int seed = -1);
630 void game_post_level_init();
631 void game_do_frame();
632 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
633 void game_reset_time();
634 void game_show_framerate(); // draws framerate in lower right corner
636 int Game_no_clear = 0;
638 int Pofview_running = 0;
639 int Nebedit_running = 0;
641 typedef struct big_expl_flash {
642 float max_flash_intensity; // max intensity
643 float cur_flash_intensity; // cur intensity
644 int flash_start; // start time
647 #define FRAME_FILTER 16
649 #define DEFAULT_SKILL_LEVEL 1
650 int Game_skill_level = DEFAULT_SKILL_LEVEL;
652 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
653 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
655 #define EXE_FNAME ("fs2.exe")
656 #define LAUNCHER_FNAME ("freespace2.exe")
658 // JAS: Code for warphole camera.
659 // Needs to be cleaned up.
660 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
661 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
662 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
663 matrix Camera_orient = IDENTITY_MATRIX;
664 float Camera_damping = 1.0f;
665 float Camera_time = 0.0f;
666 float Warpout_time = 0.0f;
667 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
668 int Warpout_sound = -1;
670 int Use_joy_mouse = 0;
671 int Use_palette_flash = 1;
673 int Use_fullscreen_at_startup = 0;
675 int Show_area_effect = 0;
676 object *Last_view_target = NULL;
678 int dogfight_blown = 0;
681 float frametimes[FRAME_FILTER];
682 float frametotal = 0.0f;
686 int Show_framerate = 0;
688 int Show_framerate = 1;
691 int Framerate_cap = 120;
694 int Show_target_debug_info = 0;
695 int Show_target_weapons = 0;
697 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
699 int Debug_octant = -1;
701 fix Game_time_compression = F1_0;
703 // if the ships.tbl the player has is valid
704 int Game_ships_tbl_valid = 0;
706 // if the weapons.tbl the player has is valid
707 int Game_weapons_tbl_valid = 0;
711 extern int Player_attacking_enabled;
715 int Pre_player_entry;
717 int Fred_running = 0;
718 char Game_current_mission_filename[MAX_FILENAME_LEN];
719 int game_single_step = 0;
720 int last_single_step=0;
722 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
723 extern int MSG_WINDOW_Y_START;
724 extern int MSG_WINDOW_HEIGHT;
726 int game_zbuffer = 1;
727 //static int Game_music_paused;
728 static int Game_paused;
732 #define EXPIRE_BAD_CHECKSUM 1
733 #define EXPIRE_BAD_TIME 2
735 extern void ssm_init();
736 extern void ssm_level_init();
737 extern void ssm_process();
739 // static variable to contain the time this version was built
740 // commented out for now until
741 // I figure out how to get the username into the file
742 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
744 // defines and variables used for dumping frame for making trailers.
746 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
747 int Debug_dump_trigger = 0;
748 int Debug_dump_frame_count;
749 int Debug_dump_frame_num = 0;
750 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
753 // amount of time to wait after the player has died before we display the death died popup
754 #define PLAYER_DIED_POPUP_WAIT 2500
755 int Player_died_popup_wait = -1;
756 int Player_multi_died_check = -1;
758 // builtin mission list stuff
760 int Game_builtin_mission_count = 6;
761 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
762 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
763 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
764 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
765 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
766 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
767 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
769 #elif defined(PD_BUILD)
770 int Game_builtin_mission_count = 4;
771 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
772 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
773 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
774 { "sm1-01", (FSB_FROM_VOLITION), "" },
775 { "sm1-05", (FSB_FROM_VOLITION), "" },
777 #elif defined(MULTIPLAYER_BETA)
778 int Game_builtin_mission_count = 17;
779 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
781 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
782 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
783 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
784 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
785 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
786 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
787 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
788 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
789 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
790 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
791 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
792 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
793 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
794 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
795 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
796 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
797 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
799 #elif defined(OEM_BUILD)
800 int Game_builtin_mission_count = 17;
801 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
802 // oem version - act 1 only
803 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
806 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
807 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
808 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
809 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
810 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
811 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
812 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
813 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
814 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
815 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
816 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
817 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
818 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
819 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
820 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
821 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
824 int Game_builtin_mission_count = 92;
825 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
826 // single player campaign
827 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
830 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
831 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
832 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
833 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
835 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
836 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
838 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
839 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
841 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
842 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
843 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
844 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
845 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
846 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
847 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
848 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
851 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
853 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
854 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
858 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
859 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
864 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
865 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
866 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
867 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
868 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
869 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
870 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
871 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
872 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
873 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
874 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
876 // multiplayer missions
879 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
922 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
927 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
933 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
934 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
935 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
936 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
941 // Internal function prototypes
942 void game_maybe_draw_mouse(float frametime);
943 void init_animating_pointer();
944 void load_animating_pointer(char *filename, int dx, int dy);
945 void unload_animating_pointer();
946 void game_do_training_checks();
947 void game_shutdown(void);
948 void game_show_event_debug(float frametime);
949 void game_event_debug_init();
951 void demo_upsell_show_screens();
952 void game_start_subspace_ambient_sound();
953 void game_stop_subspace_ambient_sound();
954 void verify_ships_tbl();
955 void verify_weapons_tbl();
956 void display_title_screen();
958 // loading background filenames
959 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
960 "LoadingBG", // GR_640
961 "2_LoadingBG" // GR_1024
965 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
966 "Loading.ani", // GR_640
967 "2_Loading.ani" // GR_1024
970 #if defined(FS2_DEMO)
971 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
975 #elif defined(OEM_BUILD)
976 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
983 char Game_CDROM_dir[MAX_PATH_LEN];
986 // How much RAM is on this machine. Set in WinMain
987 uint Freespace_total_ram = 0;
990 float Game_flash_red = 0.0f;
991 float Game_flash_green = 0.0f;
992 float Game_flash_blue = 0.0f;
993 float Sun_spot = 0.0f;
994 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
996 // game shudder stuff (in ms)
997 int Game_shudder_time = -1;
998 int Game_shudder_total = 0;
999 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1002 sound_env Game_sound_env;
1003 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1004 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1006 int Game_sound_env_update_timestamp;
1008 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1011 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1013 fs_builtin_mission *game_find_builtin_mission(char *filename)
1017 // look through all existing builtin missions
1018 for(idx=0; idx<Game_builtin_mission_count; idx++){
1019 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1020 return &Game_builtin_mission_list[idx];
1028 int game_get_default_skill_level()
1030 return DEFAULT_SKILL_LEVEL;
1034 void game_flash_reset()
1036 Game_flash_red = 0.0f;
1037 Game_flash_green = 0.0f;
1038 Game_flash_blue = 0.0f;
1040 Big_expl_flash.max_flash_intensity = 0.0f;
1041 Big_expl_flash.cur_flash_intensity = 0.0f;
1042 Big_expl_flash.flash_start = 0;
1045 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1046 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1048 void game_framerate_check_init()
1050 // zero critical time
1051 Gf_critical_time = 0.0f;
1054 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1055 // if this is a glide card
1056 if(gr_screen.mode == GR_GLIDE){
1058 extern GrHwConfiguration hwconfig;
1061 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1062 Gf_critical = 15.0f;
1066 Gf_critical = 10.0f;
1071 Gf_critical = 15.0f;
1074 // d3d. only care about good cards here I guess (TNT)
1076 Gf_critical = 15.0f;
1079 // if this is a glide card
1080 if(gr_screen.mode == GR_GLIDE){
1082 extern GrHwConfiguration hwconfig;
1085 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1086 Gf_critical = 25.0f;
1090 Gf_critical = 20.0f;
1095 Gf_critical = 25.0f;
1098 // d3d. only care about good cards here I guess (TNT)
1100 Gf_critical = 25.0f;
1105 extern float Framerate;
1106 void game_framerate_check()
1110 // if the current framerate is above the critical level, add frametime
1111 if(Framerate >= Gf_critical){
1112 Gf_critical_time += flFrametime;
1115 if(!Show_framerate){
1119 // display if we're above the critical framerate
1120 if(Framerate < Gf_critical){
1121 gr_set_color_fast(&Color_bright_red);
1122 gr_string(200, y_start, "Framerate warning");
1127 // display our current pct of good frametime
1128 if(f2fl(Missiontime) >= 0.0f){
1129 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1132 gr_set_color_fast(&Color_bright_green);
1134 gr_set_color_fast(&Color_bright_red);
1137 gr_printf(200, y_start, "%d%%", (int)pct);
1144 // Adds a flash effect. These can be positive or negative.
1145 // The range will get capped at around -1 to 1, so stick
1146 // with a range like that.
1147 void game_flash( float r, float g, float b )
1149 Game_flash_red += r;
1150 Game_flash_green += g;
1151 Game_flash_blue += b;
1153 if ( Game_flash_red < -1.0f ) {
1154 Game_flash_red = -1.0f;
1155 } else if ( Game_flash_red > 1.0f ) {
1156 Game_flash_red = 1.0f;
1159 if ( Game_flash_green < -1.0f ) {
1160 Game_flash_green = -1.0f;
1161 } else if ( Game_flash_green > 1.0f ) {
1162 Game_flash_green = 1.0f;
1165 if ( Game_flash_blue < -1.0f ) {
1166 Game_flash_blue = -1.0f;
1167 } else if ( Game_flash_blue > 1.0f ) {
1168 Game_flash_blue = 1.0f;
1173 // Adds a flash for Big Ship explosions
1174 // cap range from 0 to 1
1175 void big_explosion_flash(float flash)
1177 Big_expl_flash.flash_start = timestamp(1);
1181 } else if (flash < 0.0f) {
1185 Big_expl_flash.max_flash_intensity = flash;
1186 Big_expl_flash.cur_flash_intensity = 0.0f;
1189 // Amount to diminish palette towards normal, per second.
1190 #define DIMINISH_RATE 0.75f
1191 #define SUN_DIMINISH_RATE 6.00f
1195 float sn_glare_scale = 1.7f;
1198 dc_get_arg(ARG_FLOAT);
1199 sn_glare_scale = Dc_arg_float;
1202 float Supernova_last_glare = 0.0f;
1203 void game_sunspot_process(float frametime)
1207 float Sun_spot_goal = 0.0f;
1210 sn_stage = supernova_active();
1212 // sunspot differently based on supernova stage
1214 // approaching. player still in control
1217 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1220 light_get_global_dir(&light_dir, 0);
1222 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1225 // scale it some more
1226 dot = dot * (0.5f + (pct * 0.5f));
1229 Sun_spot_goal += (dot * sn_glare_scale);
1232 // draw the sun glow
1233 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1234 // draw the glow for this sun
1235 stars_draw_sun_glow(0);
1238 Supernova_last_glare = Sun_spot_goal;
1241 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1244 Sun_spot_goal = 0.9f;
1245 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1247 if(Sun_spot_goal > 1.0f){
1248 Sun_spot_goal = 1.0f;
1251 Sun_spot_goal *= sn_glare_scale;
1252 Supernova_last_glare = Sun_spot_goal;
1255 // fade to white. display dead popup
1258 Supernova_last_glare += (2.0f * flFrametime);
1259 if(Supernova_last_glare > 2.0f){
1260 Supernova_last_glare = 2.0f;
1263 Sun_spot_goal = Supernova_last_glare;
1270 // check sunspots for all suns
1271 n_lights = light_get_global_count();
1274 for(idx=0; idx<n_lights; idx++){
1275 //(vector *eye_pos, matrix *eye_orient)
1276 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1279 light_get_global_dir(&light_dir, idx);
1281 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1283 Sun_spot_goal += (float)pow(dot,85.0f);
1285 // draw the glow for this sun
1286 stars_draw_sun_glow(idx);
1288 Sun_spot_goal = 0.0f;
1294 Sun_spot_goal = 0.0f;
1298 float dec_amount = frametime*SUN_DIMINISH_RATE;
1300 if ( Sun_spot < Sun_spot_goal ) {
1301 Sun_spot += dec_amount;
1302 if ( Sun_spot > Sun_spot_goal ) {
1303 Sun_spot = Sun_spot_goal;
1305 } else if ( Sun_spot > Sun_spot_goal ) {
1306 Sun_spot -= dec_amount;
1307 if ( Sun_spot < Sun_spot_goal ) {
1308 Sun_spot = Sun_spot_goal;
1314 // Call once a frame to diminish the
1315 // flash effect to 0.
1316 void game_flash_diminish(float frametime)
1318 float dec_amount = frametime*DIMINISH_RATE;
1320 if ( Game_flash_red > 0.0f ) {
1321 Game_flash_red -= dec_amount;
1322 if ( Game_flash_red < 0.0f )
1323 Game_flash_red = 0.0f;
1325 Game_flash_red += dec_amount;
1326 if ( Game_flash_red > 0.0f )
1327 Game_flash_red = 0.0f;
1330 if ( Game_flash_green > 0.0f ) {
1331 Game_flash_green -= dec_amount;
1332 if ( Game_flash_green < 0.0f )
1333 Game_flash_green = 0.0f;
1335 Game_flash_green += dec_amount;
1336 if ( Game_flash_green > 0.0f )
1337 Game_flash_green = 0.0f;
1340 if ( Game_flash_blue > 0.0f ) {
1341 Game_flash_blue -= dec_amount;
1342 if ( Game_flash_blue < 0.0f )
1343 Game_flash_blue = 0.0f;
1345 Game_flash_blue += dec_amount;
1346 if ( Game_flash_blue > 0.0f )
1347 Game_flash_blue = 0.0f;
1350 // update big_explosion_cur_flash
1351 #define TIME_UP 1500
1352 #define TIME_DOWN 2500
1353 int duration = TIME_UP + TIME_DOWN;
1354 int time = timestamp_until(Big_expl_flash.flash_start);
1355 if (time > -duration) {
1357 if (time < TIME_UP) {
1358 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1361 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1365 if ( Use_palette_flash ) {
1367 // static int or=0, og=0, ob=0;
1369 // Change the 200 to change the color range of colors.
1370 r = fl2i( Game_flash_red*128.0f );
1371 g = fl2i( Game_flash_green*128.0f );
1372 b = fl2i( Game_flash_blue*128.0f );
1374 if ( Sun_spot > 0.0f ) {
1375 r += fl2i(Sun_spot*128.0f);
1376 g += fl2i(Sun_spot*128.0f);
1377 b += fl2i(Sun_spot*128.0f);
1380 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1381 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1382 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1383 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1386 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1387 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1388 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1390 if ( (r!=0) || (g!=0) || (b!=0) ) {
1391 gr_flash( r, g, b );
1393 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1404 void game_level_close()
1406 // De-Initialize the game subsystems
1407 message_mission_shutdown();
1408 event_music_level_close();
1409 game_stop_looped_sounds();
1411 obj_snd_level_close(); // uninit object-linked persistant sounds
1412 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1413 anim_level_close(); // stop and clean up any anim instances
1414 shockwave_level_close();
1415 fireball_level_close();
1417 mission_event_shutdown();
1418 asteroid_level_close();
1419 model_cache_reset(); // Reset/free all the model caching stuff
1420 flak_level_close(); // unload flak stuff
1421 neb2_level_close(); // shutdown gaseous nebula stuff
1424 mflash_level_close();
1426 audiostream_unpause_all();
1431 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1432 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1433 void game_level_init(int seed)
1435 // seed the random number generator
1437 // if no seed was passed, seed the generator either from the time value, or from the
1438 // netgame security flags -- ensures that all players in multiplayer game will have the
1439 // same randon number sequence (with static rand functions)
1440 if ( Game_mode & GM_NORMAL ) {
1441 Game_level_seed = time(NULL);
1443 Game_level_seed = Netgame.security;
1446 // mwa 9/17/98 -- maybe this assert isn't needed????
1447 Assert( !(Game_mode & GM_MULTIPLAYER) );
1448 Game_level_seed = seed;
1450 srand( Game_level_seed );
1452 // semirand function needs to get re-initted every time in multiplayer
1453 if ( Game_mode & GM_MULTIPLAYER ){
1459 Key_normal_game = (Game_mode & GM_NORMAL);
1462 Game_shudder_time = -1;
1464 // Initialize the game subsystems
1465 // timestamp_reset(); // Must be inited before everything else
1467 game_reset_time(); // resets time, and resets saved time too
1469 obj_init(); // Must be inited before the other systems
1470 model_free_all(); // Free all existing models
1471 mission_brief_common_init(); // Free all existing briefing/debriefing text
1472 weapon_level_init();
1473 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1475 player_level_init();
1476 shipfx_flash_init(); // Init the ship gun flash system.
1477 game_flash_reset(); // Reset the flash effect
1478 particle_init(); // Reset the particle system
1482 shield_hit_init(); // Initialize system for showing shield hits
1483 radar_mission_init();
1484 mission_init_goals();
1487 obj_snd_level_init(); // init object-linked persistant sounds
1489 shockwave_level_init();
1490 afterburner_level_init();
1491 scoring_level_init( &Player->stats );
1493 asteroid_level_init();
1494 control_config_clear_used_status();
1495 collide_ship_ship_sounds_init();
1497 Pre_player_entry = 1; // Means the player has not yet entered.
1498 Entry_delay_time = 0; // Could get overwritten in mission read.
1499 fireball_preload(); // page in warphole bitmaps
1501 flak_level_init(); // initialize flak - bitmaps, etc
1502 ct_level_init(); // initialize ships contrails, etc
1503 awacs_level_init(); // initialize AWACS
1504 beam_level_init(); // initialize beam weapons
1505 mflash_level_init();
1507 supernova_level_init();
1509 // multiplayer dogfight hack
1512 shipfx_engine_wash_level_init();
1516 Last_view_target = NULL;
1521 // campaign wasn't ended
1522 Campaign_ended_in_mission = 0;
1525 // called when a mission is over -- does server specific stuff.
1526 void freespace_stop_mission()
1529 Game_mode &= ~GM_IN_MISSION;
1532 // called at frame interval to process networking stuff
1533 void game_do_networking()
1535 Assert( Net_player != NULL );
1536 if (!(Game_mode & GM_MULTIPLAYER)){
1540 // see if this player should be reading/writing data. Bit is set when at join
1541 // screen onward until quits back to main menu.
1542 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1546 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1549 multi_pause_do_frame();
1554 // Loads the best palette for this level, based
1555 // on nebula color and hud color. You could just call palette_load_table with
1556 // the appropriate filename, but who wants to do that.
1557 void game_load_palette()
1559 char palette_filename[1024];
1561 // We only use 3 hud colors right now
1562 // Assert( HUD_config.color >= 0 );
1563 // Assert( HUD_config.color <= 2 );
1565 Assert( Mission_palette >= 0 );
1566 Assert( Mission_palette <= 98 );
1568 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1569 strcpy( palette_filename, NOX("gamepalette-subspace") );
1571 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1574 mprintf(( "Loading palette %s\n", palette_filename ));
1576 // palette_load_table(palette_filename);
1579 void game_post_level_init()
1581 // Stuff which gets called after mission is loaded. Because player isn't created until
1582 // after mission loads, some things must get initted after the level loads
1584 model_level_post_init();
1587 hud_setup_escort_list();
1588 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1594 game_event_debug_init();
1597 training_mission_init();
1598 asteroid_create_all();
1600 game_framerate_check_init();
1604 // An estimate as to how high the count passed to game_loading_callback will go.
1605 // This is just a guess, it seems to always be about the same. The count is
1606 // proportional to the code being executed, not the time, so this works good
1607 // for a bar, assuming the code does about the same thing each time you
1608 // load a level. You can find this value by looking at the return value
1609 // of game_busy_callback(NULL), which I conveniently print out to the
1610 // debug output window with the '=== ENDING LOAD ==' stuff.
1611 //#define COUNT_ESTIMATE 3706
1612 #define COUNT_ESTIMATE 1111
1614 int Game_loading_callback_inited = 0;
1616 int Game_loading_background = -1;
1617 anim * Game_loading_ani = NULL;
1618 anim_instance *Game_loading_ani_instance;
1619 int Game_loading_frame=-1;
1621 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1630 // This gets called 10x per second and count is the number of times
1631 // game_busy() has been called since the current callback function
1633 void game_loading_callback(int count)
1635 game_do_networking();
1637 Assert( Game_loading_callback_inited==1 );
1638 Assert( Game_loading_ani != NULL );
1640 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1641 if ( framenum > Game_loading_ani->total_frames-1 ) {
1642 framenum = Game_loading_ani->total_frames-1;
1643 } else if ( framenum < 0 ) {
1648 while ( Game_loading_frame < framenum ) {
1649 Game_loading_frame++;
1650 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1654 if ( cbitmap > -1 ) {
1655 if ( Game_loading_background > -1 ) {
1656 gr_set_bitmap( Game_loading_background );
1660 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1661 gr_set_bitmap( cbitmap );
1662 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1664 bm_release(cbitmap);
1670 void game_loading_callback_init()
1672 Assert( Game_loading_callback_inited==0 );
1674 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1675 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1678 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1679 Assert( Game_loading_ani != NULL );
1680 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1681 Assert( Game_loading_ani_instance != NULL );
1682 Game_loading_frame = -1;
1684 Game_loading_callback_inited = 1;
1686 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1691 void game_loading_callback_close()
1693 Assert( Game_loading_callback_inited==1 );
1695 // Make sure bar shows all the way over.
1696 game_loading_callback(COUNT_ESTIMATE);
1698 int real_count = game_busy_callback( NULL );
1701 Game_loading_callback_inited = 0;
1704 mprintf(( "=================== ENDING LOAD ================\n" ));
1705 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1706 mprintf(( "================================================\n" ));
1708 // to remove warnings in release build
1712 free_anim_instance(Game_loading_ani_instance);
1713 Game_loading_ani_instance = NULL;
1714 anim_free(Game_loading_ani);
1715 Game_loading_ani = NULL;
1717 bm_release( Game_loading_background );
1718 common_free_interface_palette(); // restore game palette
1719 Game_loading_background = -1;
1721 gr_set_font( FONT1 );
1724 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1726 void game_maybe_update_sound_environment()
1728 // do nothing for now
1731 // Assign the sound environment for the game, based on the current mission
1733 void game_assign_sound_environment()
1736 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1737 Game_sound_env.id = SND_ENV_DRUGGED;
1738 Game_sound_env.volume = 0.800f;
1739 Game_sound_env.damping = 1.188f;
1740 Game_sound_env.decay = 6.392f;
1742 } else if (Num_asteroids > 30) {
1743 Game_sound_env.id = SND_ENV_AUDITORIUM;
1744 Game_sound_env.volume = 0.603f;
1745 Game_sound_env.damping = 0.5f;
1746 Game_sound_env.decay = 4.279f;
1749 Game_sound_env = Game_default_sound_env;
1753 Game_sound_env = Game_default_sound_env;
1754 Game_sound_env_update_timestamp = timestamp(1);
1757 // function which gets called before actually entering the mission. It is broken down into a funciton
1758 // since it will get called in one place from a single player game and from another place for
1759 // a multiplayer game
1760 void freespace_mission_load_stuff()
1762 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1763 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1764 if(!(Game_mode & GM_STANDALONE_SERVER)){
1766 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1768 game_loading_callback_init();
1770 event_music_level_init(); // preloads the first 2 seconds for each event music track
1773 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1776 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1779 ship_assign_sound_all(); // assign engine sounds to ships
1780 game_assign_sound_environment(); // assign the sound environment for this mission
1783 // call function in missionparse.cpp to fixup player/ai stuff.
1784 mission_parse_fixup_players();
1787 // Load in all the bitmaps for this level
1792 game_loading_callback_close();
1794 // the only thing we need to call on the standalone for now.
1796 // call function in missionparse.cpp to fixup player/ai stuff.
1797 mission_parse_fixup_players();
1799 // Load in all the bitmaps for this level
1805 uint load_mission_load;
1806 uint load_post_level_init;
1807 uint load_mission_stuff;
1809 // tells the server to load the mission and initialize structures
1810 int game_start_mission()
1812 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1814 load_gl_init = time(NULL);
1816 load_gl_init = time(NULL) - load_gl_init;
1818 if (Game_mode & GM_MULTIPLAYER) {
1819 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1821 // clear multiplayer stats
1822 init_multiplayer_stats();
1825 load_mission_load = time(NULL);
1826 if (mission_load()) {
1827 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1828 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1829 gameseq_post_event(GS_EVENT_MAIN_MENU);
1831 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1836 load_mission_load = time(NULL) - load_mission_load;
1838 // If this is a red alert mission in campaign mode, bash wingman status
1839 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1840 red_alert_bash_wingman_status();
1843 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1844 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1845 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1846 // game_load_palette();
1849 load_post_level_init = time(NULL);
1850 game_post_level_init();
1851 load_post_level_init = time(NULL) - load_post_level_init;
1855 void Do_model_timings_test();
1856 Do_model_timings_test();
1860 load_mission_stuff = time(NULL);
1861 freespace_mission_load_stuff();
1862 load_mission_stuff = time(NULL) - load_mission_stuff;
1867 int Interface_framerate = 0;
1870 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1871 DCF_BOOL( show_framerate, Show_framerate )
1872 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1873 DCF_BOOL( show_target_weapons, Show_target_weapons )
1874 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1875 DCF_BOOL( sound, Sound_enabled )
1876 DCF_BOOL( zbuffer, game_zbuffer )
1877 DCF_BOOL( shield_system, New_shield_system )
1878 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1879 DCF_BOOL( player_attacking, Player_attacking_enabled )
1880 DCF_BOOL( show_waypoints, Show_waypoints )
1881 DCF_BOOL( show_area_effect, Show_area_effect )
1882 DCF_BOOL( show_net_stats, Show_net_stats )
1883 DCF_BOOL( log, Log_debug_output_to_file )
1884 DCF_BOOL( training_msg_method, Training_msg_method )
1885 DCF_BOOL( show_player_pos, Show_player_pos )
1886 DCF_BOOL(i_framerate, Interface_framerate )
1888 DCF(show_mem,"Toggles showing mem usage")
1891 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1892 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1893 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1894 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1900 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1902 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1903 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1907 DCF(show_cpu,"Toggles showing cpu usage")
1910 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1911 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1912 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1913 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1919 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1921 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1922 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1929 // AL 4-8-98: always allow players to display their framerate
1932 DCF_BOOL( show_framerate, Show_framerate )
1939 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1942 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1943 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1944 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1945 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1947 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" );
1948 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1950 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1953 DCF(palette_flash,"Toggles palette flash effect on/off")
1956 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1957 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1958 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1959 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1961 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1962 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1965 int Use_low_mem = 0;
1967 DCF(low_mem,"Uses low memory settings regardless of RAM")
1970 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1971 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1972 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1973 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1975 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1976 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1978 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1984 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1987 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1988 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1989 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1990 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1992 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1993 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1994 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1998 int Framerate_delay = 0;
2000 float Freespace_gamma = 1.0f;
2002 DCF(gamma,"Sets Gamma factor")
2005 dc_get_arg(ARG_FLOAT|ARG_NONE);
2006 if ( Dc_arg_type & ARG_FLOAT ) {
2007 Freespace_gamma = Dc_arg_float;
2009 dc_printf( "Gamma reset to 1.0f\n" );
2010 Freespace_gamma = 1.0f;
2012 if ( Freespace_gamma < 0.1f ) {
2013 Freespace_gamma = 0.1f;
2014 } else if ( Freespace_gamma > 5.0f ) {
2015 Freespace_gamma = 5.0f;
2017 gr_set_gamma(Freespace_gamma);
2019 char tmp_gamma_string[32];
2020 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2021 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2025 dc_printf( "Usage: gamma <float>\n" );
2026 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2027 Dc_status = 0; // don't print status if help is printed. Too messy.
2031 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2040 Game_current_mission_filename[0] = 0;
2042 // seed the random number generator
2043 Game_init_seed = time(NULL);
2044 srand( Game_init_seed );
2046 Framerate_delay = 0;
2052 extern void bm_init();
2058 // Initialize the timer before the os
2066 GetCurrentDirectory(1024, whee);
2069 getcwd (whee, 1024);
2072 strcat(whee, EXE_FNAME);
2074 //Initialize the libraries
2075 s1 = timer_get_milliseconds();
2076 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2079 e1 = timer_get_milliseconds();
2081 // time a bunch of cfopens
2083 s2 = timer_get_milliseconds();
2085 for(int idx=0; idx<10000; idx++){
2086 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2091 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2093 e2 = timer_get_milliseconds();
2096 if (Is_standalone) {
2097 std_init_standalone();
2099 os_init( Osreg_class_name, Osreg_app_name );
2100 os_set_title(Osreg_title);
2103 // initialize localization module. Make sure this is down AFTER initialzing OS.
2104 // int t1 = timer_get_milliseconds();
2107 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2109 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2112 // verify that he has a valid weapons.tbl
2113 verify_weapons_tbl();
2115 // Output version numbers to registry for auto patching purposes
2116 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2117 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2118 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2120 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2121 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2122 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2125 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2129 Asteroids_enabled = 1;
2132 /////////////////////////////
2134 /////////////////////////////
2139 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2140 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2142 if (!stricmp(ptr, NOX("no sound"))) {
2143 Cmdline_freespace_no_sound = 1;
2145 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2147 } else if (!stricmp(ptr, NOX("EAX"))) {
2152 if (!Is_standalone) {
2153 snd_init(use_a3d, use_eax);
2155 /////////////////////////////
2157 /////////////////////////////
2159 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2162 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);
2164 // fire up the UpdateLauncher executable
2166 PROCESS_INFORMATION pi;
2168 memset( &si, 0, sizeof(STARTUPINFO) );
2171 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2172 NULL, // pointer to command line string
2173 NULL, // pointer to process security attributes
2174 NULL, // pointer to thread security attributes
2175 FALSE, // handle inheritance flag
2176 CREATE_DEFAULT_ERROR_MODE, // creation flags
2177 NULL, // pointer to new environment block
2178 NULL, // pointer to current directory name
2179 &si, // pointer to STARTUPINFO
2180 &pi // pointer to PROCESS_INFORMATION
2183 // If the Launcher could not be started up, let the user know
2185 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2194 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2196 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);
2204 // check for hi res pack file
2205 int has_sparky_hi = 0;
2207 // check if sparky_hi exists -- access mode 0 means does file exist
2210 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2213 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2216 // see if we've got 32 bit in the string
2217 if(strstr(ptr, "32 bit")){
2224 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2226 // always 640 for E3
2227 gr_init(GR_640, GR_GLIDE);
2229 // regular or hi-res ?
2231 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2233 if(strstr(ptr, NOX("(1024x768)"))){
2235 gr_init(GR_1024, GR_GLIDE);
2237 gr_init(GR_640, GR_GLIDE);
2240 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2242 // always 640 for E3
2244 gr_init(GR_640, GR_DIRECT3D, depth);
2246 // regular or hi-res ?
2248 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2250 if(strstr(ptr, NOX("(1024x768)"))){
2254 gr_init(GR_1024, GR_DIRECT3D, depth);
2258 gr_init(GR_640, GR_DIRECT3D, depth);
2264 if ( Use_fullscreen_at_startup && !Is_standalone) {
2265 gr_init(GR_640, GR_DIRECTDRAW);
2267 gr_init(GR_640, GR_SOFTWARE);
2270 if ( !Is_standalone ) {
2271 gr_init(GR_640, GR_DIRECTDRAW);
2273 gr_init(GR_640, GR_SOFTWARE);
2278 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2279 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2280 gr_init(GR_1024, GR_OPENGL);
2282 gr_init(GR_640, GR_OPENGL);
2286 gr_init(GR_640, GR_SOFTWARE);
2291 extern int Gr_inited;
2292 if(trying_d3d && !Gr_inited){
2293 extern char Device_init_error[512];
2295 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2304 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2305 Freespace_gamma = (float)atof(ptr);
2306 if ( Freespace_gamma == 0.0f ) {
2307 Freespace_gamma = 1.80f;
2308 } else if ( Freespace_gamma < 0.1f ) {
2309 Freespace_gamma = 0.1f;
2310 } else if ( Freespace_gamma > 5.0f ) {
2311 Freespace_gamma = 5.0f;
2313 char tmp_gamma_string[32];
2314 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2315 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2317 gr_set_gamma(Freespace_gamma);
2319 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2322 display_title_screen();
2326 // attempt to load up master tracker registry info (login and password)
2327 Multi_tracker_id = -1;
2329 // pxo login and password
2330 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2332 nprintf(("Network","Error reading in PXO login data\n"));
2333 strcpy(Multi_tracker_login,"");
2335 strcpy(Multi_tracker_login,ptr);
2337 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2339 nprintf(("Network","Error reading PXO password\n"));
2340 strcpy(Multi_tracker_passwd,"");
2342 strcpy(Multi_tracker_passwd,ptr);
2345 // pxo squad name and password
2346 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2348 nprintf(("Network","Error reading in PXO squad name\n"));
2349 strcpy(Multi_tracker_squad_name, "");
2351 strcpy(Multi_tracker_squad_name, ptr);
2354 // If less than 48MB of RAM, use low memory model.
2355 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2356 mprintf(( "Using normal memory settings...\n" ));
2357 bm_set_low_mem(1); // Use every other frame of bitmaps
2359 mprintf(( "Using high memory settings...\n" ));
2360 bm_set_low_mem(0); // Use all frames of bitmaps
2363 // load non-darkening pixel defs
2364 palman_load_pixels();
2366 // hud shield icon stuff
2367 hud_shield_game_init();
2369 control_config_common_init(); // sets up localization stuff in the control config
2375 gamesnd_parse_soundstbl();
2380 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2385 player_controls_init();
2388 //if(!Is_standalone){
2396 ship_init(); // read in ships.tbl
2398 mission_campaign_init(); // load in the default campaign
2400 // navmap_init(); // init the navigation map system
2401 context_help_init();
2402 techroom_intel_init(); // parse species.tbl, load intel info
2404 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2405 init_animating_pointer();
2407 mission_brief_common_init(); // Mark all the briefing structures as empty.
2408 gr_font_init(); // loads up all fonts
2410 neb2_init(); // fullneb stuff
2414 player_tips_init(); // helpful tips
2417 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2418 pilot_load_pic_list();
2419 pilot_load_squad_pic_list();
2421 load_animating_pointer(NOX("cursor"), 0, 0);
2423 // initialize alpha colors
2424 alpha_colors_init();
2427 // Game_music_paused = 0;
2434 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2435 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2437 mprintf(("cfile_init() took %d\n", e1 - s1));
2438 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2441 char transfer_text[128];
2443 float Start_time = 0.0f;
2445 float Framerate = 0.0f;
2447 float Timing_total = 0.0f;
2448 float Timing_render2 = 0.0f;
2449 float Timing_render3 = 0.0f;
2450 float Timing_flip = 0.0f;
2451 float Timing_clear = 0.0f;
2453 MONITOR(NumPolysDrawn);
2459 void game_get_framerate()
2461 char text[128] = "";
2463 if ( frame_int == -1 ) {
2465 for (i=0; i<FRAME_FILTER; i++ ) {
2466 frametimes[i] = 0.0f;
2471 frametotal -= frametimes[frame_int];
2472 frametotal += flFrametime;
2473 frametimes[frame_int] = flFrametime;
2474 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2476 if ( frametotal != 0.0 ) {
2477 if ( Framecount >= FRAME_FILTER )
2478 Framerate = FRAME_FILTER / frametotal;
2480 Framerate = Framecount / frametotal;
2481 sprintf( text, NOX("FPS: %.1f"), Framerate );
2483 sprintf( text, NOX("FPS: ?") );
2487 if (Show_framerate) {
2488 gr_set_color_fast(&HUD_color_debug);
2489 gr_string( 570, 2, text );
2493 void game_show_framerate()
2497 cur_time = f2fl(timer_get_approx_seconds());
2498 if (cur_time - Start_time > 30.0f) {
2499 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2500 Start_time += 1000.0f;
2503 //mprintf(( "%s\n", text ));
2506 if ( Debug_dump_frames )
2510 // possibly show control checking info
2511 control_check_indicate();
2513 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2514 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2515 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2516 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2519 if ( Show_cpu == 1 ) {
2524 dy = gr_get_font_height() + 1;
2526 gr_set_color_fast(&HUD_color_debug);
2530 extern int D3D_textures_in;
2531 extern int D3D_textures_in_frame;
2532 extern int Glide_textures_in;
2533 extern int Glide_textures_in_frame;
2534 extern int Glide_explosion_vram;
2535 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2537 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2539 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2545 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2547 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2549 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2551 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2553 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2558 extern int Num_pairs; // Number of object pairs that were checked.
2559 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2562 extern int Num_pairs_checked; // What percent of object pairs were checked.
2563 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2565 Num_pairs_checked = 0;
2569 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2572 if ( Timing_total > 0.01f ) {
2573 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2575 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2577 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2579 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2581 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2591 dy = gr_get_font_height() + 1;
2593 gr_set_color_fast(&HUD_color_debug);
2596 extern int TotalRam;
2597 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2602 extern int Model_ram;
2603 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2607 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2609 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2611 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2615 extern int D3D_textures_in;
2616 extern int Glide_textures_in;
2617 extern int Glide_textures_in_frame;
2618 extern int Glide_explosion_vram;
2619 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2621 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2623 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2632 if ( Show_player_pos ) {
2636 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));
2639 MONITOR_INC(NumPolys, modelstats_num_polys);
2640 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2641 MONITOR_INC(NumVerts, modelstats_num_verts );
2643 modelstats_num_polys = 0;
2644 modelstats_num_polys_drawn = 0;
2645 modelstats_num_verts = 0;
2646 modelstats_num_sortnorms = 0;
2650 void game_show_standalone_framerate()
2652 float frame_rate=30.0f;
2653 if ( frame_int == -1 ) {
2655 for (i=0; i<FRAME_FILTER; i++ ) {
2656 frametimes[i] = 0.0f;
2661 frametotal -= frametimes[frame_int];
2662 frametotal += flFrametime;
2663 frametimes[frame_int] = flFrametime;
2664 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2666 if ( frametotal != 0.0 ) {
2667 if ( Framecount >= FRAME_FILTER ){
2668 frame_rate = FRAME_FILTER / frametotal;
2670 frame_rate = Framecount / frametotal;
2673 std_set_standalone_fps(frame_rate);
2677 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2678 void game_show_time_left()
2682 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2683 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2684 // checking how much time is left
2686 if ( Mission_end_time == -1 ){
2690 diff = f2i(Mission_end_time - Missiontime);
2691 // be sure to bash to 0. diff could be negative on frame that we quit mission
2696 hud_set_default_color();
2697 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2700 //========================================================================================
2701 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2702 //========================================================================================
2706 DCF(ai_pause,"Pauses ai")
2709 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2710 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2711 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2712 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2715 obj_init_all_ships_physics();
2718 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2719 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2722 DCF(single_step,"Single steps the game")
2725 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2726 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2727 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2728 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2730 last_single_step = 0; // Make so single step waits a frame before stepping
2733 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2734 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2737 DCF_BOOL(physics_pause, physics_paused)
2738 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2739 DCF_BOOL(ai_firing, Ai_firing_enabled )
2741 // Create some simple aliases to these commands...
2742 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2743 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2744 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2745 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2746 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2749 //========================================================================================
2750 //========================================================================================
2753 void game_training_pause_do()
2757 key = game_check_key();
2759 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2766 void game_increase_skill_level()
2769 if (Game_skill_level >= NUM_SKILL_LEVELS){
2770 Game_skill_level = 0;
2774 int Player_died_time;
2776 int View_percent = 100;
2779 DCF(view, "Sets the percent of the 3d view to render.")
2782 dc_get_arg(ARG_INT);
2783 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2784 View_percent = Dc_arg_int;
2786 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2792 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2796 dc_printf("View is set to %d%%\n", View_percent );
2801 // Set the clip region for the 3d rendering window
2802 void game_set_view_clip()
2804 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2805 // Set the clip region for the letterbox "dead view"
2806 int yborder = gr_screen.max_h/4;
2808 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2809 // J.S. I've changed my ways!! See the new "no constants" code!!!
2810 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2812 // Set the clip region for normal view
2813 if ( View_percent >= 100 ) {
2816 int xborder, yborder;
2818 if ( View_percent < 5 ) {
2822 float fp = i2fl(View_percent)/100.0f;
2823 int fi = fl2i(fl_sqrt(fp)*100.0f);
2824 if ( fi > 100 ) fi=100;
2826 xborder = ( gr_screen.max_w*(100-fi) )/200;
2827 yborder = ( gr_screen.max_h*(100-fi) )/200;
2829 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2835 void show_debug_stuff()
2838 int laser_count = 0, missile_count = 0;
2840 for (i=0; i<MAX_OBJECTS; i++) {
2841 if (Objects[i].type == OBJ_WEAPON){
2842 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2844 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2850 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2853 extern int Tool_enabled;
2858 int tst_bitmap = -1;
2860 float tst_offset, tst_offset_total;
2863 void game_tst_frame_pre()
2871 g3_rotate_vertex(&v, &tst_pos);
2872 g3_project_vertex(&v);
2875 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2879 // big ship? always tst
2881 // within 3000 meters
2882 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2886 // within 300 meters
2887 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2894 void game_tst_frame()
2904 tst_time = time(NULL);
2906 // load the tst bitmap
2907 switch((int)frand_range(0.0f, 3.0)){
2909 tst_bitmap = bm_load("ig_jim");
2911 mprintf(("TST 0\n"));
2915 tst_bitmap = bm_load("ig_kan");
2917 mprintf(("TST 1\n"));
2921 tst_bitmap = bm_load("ig_jim");
2923 mprintf(("TST 2\n"));
2927 tst_bitmap = bm_load("ig_kan");
2929 mprintf(("TST 3\n"));
2938 // get the tst bitmap dimensions
2940 bm_get_info(tst_bitmap, &w, &h);
2943 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2945 snd_play(&Snds[SND_VASUDAN_BUP]);
2947 // tst x and direction
2951 tst_offset_total = (float)w;
2952 tst_offset = (float)w;
2954 tst_x = (float)gr_screen.max_w;
2955 tst_offset_total = (float)-w;
2956 tst_offset = (float)w;
2964 float diff = (tst_offset_total / 0.5f) * flFrametime;
2970 tst_offset -= fl_abs(diff);
2971 } else if(tst_mode == 2){
2974 tst_offset -= fl_abs(diff);
2978 gr_set_bitmap(tst_bitmap);
2979 gr_bitmap((int)tst_x, (int)tst_y);
2982 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2986 // if we passed the switch point
2987 if(tst_offset <= 0.0f){
2992 tst_stamp = timestamp(1000);
2993 tst_offset = fl_abs(tst_offset_total);
3004 void game_tst_mark(object *objp, ship *shipp)
3013 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3016 sip = &Ship_info[shipp->ship_info_index];
3023 tst_pos = objp->pos;
3024 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3030 extern void render_shields();
3032 void player_repair_frame(float frametime)
3034 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3036 for(idx=0;idx<MAX_PLAYERS;idx++){
3039 np = &Net_players[idx];
3041 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)){
3043 // don't rearm/repair if the player is dead or dying/departing
3044 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3045 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3050 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3051 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3057 #define NUM_FRAMES_TEST 300
3058 #define NUM_MIXED_SOUNDS 16
3059 void do_timing_test(float flFrametime)
3061 static int framecount = 0;
3062 static int test_running = 0;
3063 static float test_time = 0.0f;
3065 static int snds[NUM_MIXED_SOUNDS];
3068 if ( test_running ) {
3070 test_time += flFrametime;
3071 if ( framecount >= NUM_FRAMES_TEST ) {
3073 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3074 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3079 if ( Test_begin == 1 ) {
3085 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3088 // start looping digital sounds
3089 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3090 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3097 DCF(dcf_fov, "Change the field of view")
3100 dc_get_arg(ARG_FLOAT|ARG_NONE);
3101 if ( Dc_arg_type & ARG_NONE ) {
3102 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3103 dc_printf( "Zoom factor reset\n" );
3105 if ( Dc_arg_type & ARG_FLOAT ) {
3106 if (Dc_arg_float < 0.25f) {
3107 Viewer_zoom = 0.25f;
3108 dc_printf("Zoom factor pinned at 0.25.\n");
3109 } else if (Dc_arg_float > 1.25f) {
3110 Viewer_zoom = 1.25f;
3111 dc_printf("Zoom factor pinned at 1.25.\n");
3113 Viewer_zoom = Dc_arg_float;
3119 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3122 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3126 DCF(framerate_cap, "Sets the framerate cap")
3129 dc_get_arg(ARG_INT);
3130 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3131 Framerate_cap = Dc_arg_int;
3133 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3139 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3140 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3141 dc_printf("[n] must be from 1 to 120.\n");
3145 if ( Framerate_cap )
3146 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3148 dc_printf("There is no framerate cap currently active.\n");
3152 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3153 int Show_viewing_from_self = 0;
3155 void say_view_target()
3157 object *view_target;
3159 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3160 view_target = &Objects[Player_ai->target_objnum];
3162 view_target = Player_obj;
3164 if (Game_mode & GM_DEAD) {
3165 if (Player_ai->target_objnum != -1)
3166 view_target = &Objects[Player_ai->target_objnum];
3169 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3170 if (view_target != Player_obj){
3172 char *view_target_name = NULL;
3173 switch(Objects[Player_ai->target_objnum].type) {
3175 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3178 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3179 Viewer_mode &= ~VM_OTHER_SHIP;
3181 case OBJ_JUMP_NODE: {
3182 char jump_node_name[128];
3183 strcpy(jump_node_name, XSTR( "jump node", 184));
3184 view_target_name = jump_node_name;
3185 Viewer_mode &= ~VM_OTHER_SHIP;
3194 if ( view_target_name ) {
3195 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3196 Show_viewing_from_self = 1;
3199 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3200 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3201 Show_viewing_from_self = 1;
3203 if (Show_viewing_from_self)
3204 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3209 Last_view_target = view_target;
3213 float Game_hit_x = 0.0f;
3214 float Game_hit_y = 0.0f;
3216 // Reset at the beginning of each frame
3217 void game_whack_reset()
3223 // Apply a 2d whack to the player
3224 void game_whack_apply( float x, float y )
3226 // Do some force feedback
3227 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3233 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3236 // call to apply a "shudder"
3237 void game_shudder_apply(int time, float intensity)
3239 Game_shudder_time = timestamp(time);
3240 Game_shudder_total = time;
3241 Game_shudder_intensity = intensity;
3244 #define FF_SCALE 10000
3245 void apply_hud_shake(matrix *eye_orient)
3247 if (Viewer_obj == Player_obj) {
3248 physics_info *pi = &Player_obj->phys_info;
3256 // Make eye shake due to afterburner
3257 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3260 dtime = timestamp_until(pi->afterburner_decay);
3264 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3265 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3268 // Make eye shake due to engine wash
3270 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3273 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3274 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3276 // get the intensity
3277 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3281 vm_vec_rand_vec_quick(&rand_vec);
3284 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3288 // make hud shake due to shuddering
3289 if(Game_shudder_time != -1){
3290 // if the timestamp has elapsed
3291 if(timestamp_elapsed(Game_shudder_time)){
3292 Game_shudder_time = -1;
3294 // otherwise apply some shudder
3298 dtime = timestamp_until(Game_shudder_time);
3302 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));
3303 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));
3308 vm_angles_2_matrix(&tm, &tangles);
3309 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3310 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3311 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3312 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3317 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3319 // Player's velocity just before he blew up. Used to keep camera target moving.
3320 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3322 // Set eye_pos and eye_orient based on view mode.
3323 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3327 static int last_Viewer_mode = 0;
3328 static int last_Game_mode = 0;
3329 static int last_Viewer_objnum = -1;
3331 // This code is supposed to detect camera "cuts"... like going between
3334 // determine if we need to regenerate the nebula
3335 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3336 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3337 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3338 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3339 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3340 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3341 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3342 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3343 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3346 // regenerate the nebula
3350 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3351 //mprintf(( "************** Camera cut! ************\n" ));
3352 last_Viewer_mode = Viewer_mode;
3353 last_Game_mode = Game_mode;
3355 // Camera moved. Tell stars & debris to not do blurring.
3361 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3362 player_display_packlock_view();
3365 game_set_view_clip();
3367 if (Game_mode & GM_DEAD) {
3368 vector vec_to_deader, view_pos;
3371 Viewer_mode |= VM_DEAD_VIEW;
3373 if (Player_ai->target_objnum != -1) {
3374 int view_from_player = 1;
3376 if (Viewer_mode & VM_OTHER_SHIP) {
3377 // View from target.
3378 Viewer_obj = &Objects[Player_ai->target_objnum];
3380 last_Viewer_objnum = Player_ai->target_objnum;
3382 if ( Viewer_obj->type == OBJ_SHIP ) {
3383 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3384 view_from_player = 0;
3387 last_Viewer_objnum = -1;
3390 if ( view_from_player ) {
3391 // View target from player ship.
3393 *eye_pos = Player_obj->pos;
3394 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3395 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3398 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3400 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3401 dist += flFrametime * 16.0f;
3403 vm_vec_scale(&vec_to_deader, -dist);
3404 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3406 view_pos = Player_obj->pos;
3408 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3409 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3410 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3411 Dead_player_last_vel = Player_obj->phys_info.vel;
3412 //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));
3413 } else if (Player_ai->target_objnum != -1) {
3414 view_pos = Objects[Player_ai->target_objnum].pos;
3416 // Make camera follow explosion, but gradually slow down.
3417 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3418 view_pos = Player_obj->pos;
3419 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3420 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3423 *eye_pos = Dead_camera_pos;
3425 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3427 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3432 // if supernova shockwave
3433 if(supernova_camera_cut()){
3437 // call it dead view
3438 Viewer_mode |= VM_DEAD_VIEW;
3440 // set eye pos and orient
3441 supernova_set_view(eye_pos, eye_orient);
3443 // If already blown up, these other modes can override.
3444 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3445 Viewer_mode &= ~VM_DEAD_VIEW;
3447 Viewer_obj = Player_obj;
3449 if (Viewer_mode & VM_OTHER_SHIP) {
3450 if (Player_ai->target_objnum != -1){
3451 Viewer_obj = &Objects[Player_ai->target_objnum];
3452 last_Viewer_objnum = Player_ai->target_objnum;
3454 Viewer_mode &= ~VM_OTHER_SHIP;
3455 last_Viewer_objnum = -1;
3458 last_Viewer_objnum = -1;
3461 if (Viewer_mode & VM_EXTERNAL) {
3464 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3465 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3467 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3469 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3470 vm_vec_normalize(&eye_dir);
3471 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3474 // Modify the orientation based on head orientation.
3475 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3477 } else if ( Viewer_mode & VM_CHASE ) {
3480 if ( Viewer_obj->phys_info.speed < 0.1 )
3481 move_dir = Viewer_obj->orient.fvec;
3483 move_dir = Viewer_obj->phys_info.vel;
3484 vm_vec_normalize(&move_dir);
3487 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3488 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3489 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3490 vm_vec_normalize(&eye_dir);
3492 // JAS: I added the following code because if you slew up using
3493 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3494 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3495 // call because the up and the forward vector are the same. I fixed
3496 // it by adding in a fraction of the right vector all the time to the
3498 vector tmp_up = Viewer_obj->orient.uvec;
3499 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3501 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3504 // Modify the orientation based on head orientation.
3505 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3506 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3507 *eye_pos = Camera_pos;
3509 ship * shipp = &Ships[Player_obj->instance];
3511 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3512 vm_vec_normalize(&eye_dir);
3513 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3516 // get an eye position based upon the correct type of object
3517 switch(Viewer_obj->type){
3519 // make a call to get the eye point for the player object
3520 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3523 // make a call to get the eye point for the player object
3524 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3530 #ifdef JOHNS_DEBUG_CODE
3531 john_debug_stuff(&eye_pos, &eye_orient);
3537 apply_hud_shake(eye_orient);
3539 // setup neb2 rendering
3540 neb2_render_setup(eye_pos, eye_orient);
3544 extern void ai_debug_render_stuff();
3547 int Game_subspace_effect = 0;
3548 DCF_BOOL( subspace, Game_subspace_effect );
3550 // Does everything needed to render a frame
3551 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3555 g3_start_frame(game_zbuffer);
3556 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3558 // maybe offset the HUD (jitter stuff)
3559 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3560 HUD_set_offsets(Viewer_obj, !dont_offset);
3562 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3563 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3564 // must be done before ships are rendered
3565 if ( MULTIPLAYER_CLIENT ) {
3566 shield_point_multi_setup();
3569 if ( Game_subspace_effect ) {
3570 stars_draw(0,0,0,1);
3572 stars_draw(1,1,1,0);
3575 obj_render_all(obj_render);
3576 beam_render_all(); // render all beam weapons
3577 particle_render_all(); // render particles after everything else.
3578 trail_render_all(); // render missilie trails after everything else.
3579 mflash_render_all(); // render all muzzle flashes
3581 // Why do we not show the shield effect in these modes? Seems ok.
3582 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3586 // render nebula lightning
3589 // render local player nebula
3590 neb2_render_player();
3593 ai_debug_render_stuff();
3596 #ifndef RELEASE_REAL
3597 // game_framerate_check();
3601 extern void snd_spew_debug_info();
3602 snd_spew_debug_info();
3605 //================ END OF 3D RENDERING STUFF ====================
3609 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3610 hud_maybe_clear_head_area();
3611 anim_render_all(0, flFrametime);
3614 extern int Multi_display_netinfo;
3615 if(Multi_display_netinfo){
3616 extern void multi_display_netinfo();
3617 multi_display_netinfo();
3620 game_tst_frame_pre();
3623 do_timing_test(flFrametime);
3627 extern int OO_update_index;
3628 multi_rate_display(OO_update_index, 375, 0);
3633 extern void oo_display();
3640 //#define JOHNS_DEBUG_CODE 1
3642 #ifdef JOHNS_DEBUG_CODE
3643 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3645 //if ( keyd_pressed[KEY_LSHIFT] )
3647 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3649 model_subsystem *turret = tsys->system_info;
3651 if (turret->type == SUBSYSTEM_TURRET ) {
3653 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3655 ship_model_start(tobj);
3657 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3658 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3659 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3661 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3663 ship_model_stop(tobj);
3673 // following function for dumping frames for purposes of building trailers.
3676 // function to toggle state of dumping every frame into PCX when playing the game
3677 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3681 if ( Debug_dump_frames == 0 ) {
3683 Debug_dump_frames = 15;
3684 Debug_dump_trigger = 0;
3685 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3686 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3689 Debug_dump_frames = 0;
3690 Debug_dump_trigger = 0;
3691 gr_dump_frame_stop();
3692 dc_printf( "Frame dumping is now OFF\n" );
3698 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3702 if ( Debug_dump_frames == 0 ) {
3704 Debug_dump_frames = 15;
3705 Debug_dump_trigger = 1;
3706 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3707 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3710 Debug_dump_frames = 0;
3711 Debug_dump_trigger = 0;
3712 gr_dump_frame_stop();
3713 dc_printf( "Frame dumping is now OFF\n" );
3719 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3723 if ( Debug_dump_frames == 0 ) {
3725 Debug_dump_frames = 30;
3726 Debug_dump_trigger = 0;
3727 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3728 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3731 Debug_dump_frames = 0;
3732 Debug_dump_trigger = 0;
3733 gr_dump_frame_stop();
3734 dc_printf( "Frame dumping is now OFF\n" );
3740 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3744 if ( Debug_dump_frames == 0 ) {
3746 Debug_dump_frames = 30;
3747 Debug_dump_trigger = 1;
3748 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3749 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3752 Debug_dump_frames = 0;
3753 Debug_dump_trigger = 0;
3754 gr_dump_frame_stop();
3755 dc_printf( "Triggered frame dumping is now OFF\n" );
3761 void game_maybe_dump_frame()
3763 if ( !Debug_dump_frames ){
3767 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3774 Debug_dump_frame_num++;
3780 extern int Player_dead_state;
3782 // Flip the page and time how long it took.
3783 void game_flip_page_and_time_it()
3787 t1 = timer_get_fixed_seconds();
3789 t2 = timer_get_fixed_seconds();
3791 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3792 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3795 void game_simulation_frame()
3797 // blow ships up in multiplayer dogfight
3798 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){
3799 // blow up all non-player ships
3800 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3803 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3805 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)){
3806 moveup = GET_NEXT(moveup);
3809 shipp = &Ships[Objects[moveup->objnum].instance];
3810 sip = &Ship_info[shipp->ship_info_index];
3812 // only blow up small ships
3813 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3814 // function to simply explode a ship where it is currently at
3815 ship_self_destruct( &Objects[moveup->objnum] );
3818 moveup = GET_NEXT(moveup);
3824 // process AWACS stuff - do this first thing
3827 // single player, set Player hits_this_frame to 0
3828 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3829 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3830 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3834 supernova_process();
3835 if(supernova_active() >= 5){
3839 // fire targeting lasers now so that
3840 // 1 - created this frame
3841 // 2 - collide this frame
3842 // 3 - render this frame
3843 // 4 - ignored and deleted next frame
3844 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3846 ship_process_targeting_lasers();
3848 // do this here so that it works for multiplayer
3850 // get viewer direction
3851 int viewer_direction = PHYSICS_VIEWER_REAR;
3853 if(Viewer_mode == 0){
3854 viewer_direction = PHYSICS_VIEWER_FRONT;
3856 if(Viewer_mode & VM_PADLOCK_UP){
3857 viewer_direction = PHYSICS_VIEWER_UP;
3859 else if(Viewer_mode & VM_PADLOCK_REAR){
3860 viewer_direction = PHYSICS_VIEWER_REAR;
3862 else if(Viewer_mode & VM_PADLOCK_LEFT){
3863 viewer_direction = PHYSICS_VIEWER_LEFT;
3865 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3866 viewer_direction = PHYSICS_VIEWER_RIGHT;
3869 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3871 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3874 #define VM_PADLOCK_UP (1 << 7)
3875 #define VM_PADLOCK_REAR (1 << 8)
3876 #define VM_PADLOCK_LEFT (1 << 9)
3877 #define VM_PADLOCK_RIGHT (1 << 10)
3879 // evaluate mission departures and arrivals before we process all objects.
3880 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3882 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3883 // ships/wing packets.
3884 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3885 mission_parse_eval_stuff();
3888 // if we're an observer, move ourselves seperately from the standard physics
3889 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3890 obj_observer_move(flFrametime);
3893 // move all the objects now
3894 obj_move_all(flFrametime);
3896 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3897 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3898 // ship_check_cargo_all();
3899 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3900 mission_eval_goals();
3904 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3905 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3906 training_check_objectives();
3909 // do all interpolation now
3910 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3911 // client side processing of warping in effect stages
3912 multi_do_client_warp(flFrametime);
3914 // client side movement of an observer
3915 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3916 obj_observer_move(flFrametime);
3919 // move all objects - does interpolation now as well
3920 obj_move_all(flFrametime);
3923 // only process the message queue when the player is "in" the game
3924 if ( !Pre_player_entry ){
3925 message_queue_process(); // process any messages send to the player
3928 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3929 message_maybe_distort(); // maybe distort incoming message if comms damaged
3930 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3931 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3932 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3935 if(!(Game_mode & GM_STANDALONE_SERVER)){
3936 // process some stuff every frame (before frame is rendered)
3937 emp_process_local();
3939 hud_update_frame(); // update hud systems
3941 if (!physics_paused) {
3942 // Move particle system
3943 particle_move_all(flFrametime);
3945 // Move missile trails
3946 trail_move_all(flFrametime);
3948 // process muzzle flashes
3949 mflash_process_all();
3951 // Flash the gun flashes
3952 shipfx_flash_do_frame(flFrametime);
3954 shockwave_move_all(flFrametime); // update all the shockwaves
3957 // subspace missile strikes
3960 obj_snd_do_frame(); // update the object-linked persistant sounds
3961 game_maybe_update_sound_environment();
3962 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3964 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3966 if ( Game_subspace_effect ) {
3967 game_start_subspace_ambient_sound();
3973 // Maybe render and process the dead-popup
3974 void game_maybe_do_dead_popup(float frametime)
3976 if ( popupdead_is_active() ) {
3978 int choice = popupdead_do_frame(frametime);
3980 if ( Game_mode & GM_NORMAL ) {
3984 if(game_do_cd_mission_check(Game_current_mission_filename)){
3985 gameseq_post_event(GS_EVENT_ENTER_GAME);
3987 gameseq_post_event(GS_EVENT_MAIN_MENU);
3992 gameseq_post_event(GS_EVENT_END_GAME);
3997 if(game_do_cd_mission_check(Game_current_mission_filename)){
3998 gameseq_post_event(GS_EVENT_START_GAME);
4000 gameseq_post_event(GS_EVENT_MAIN_MENU);
4004 // this should only happen during a red alert mission
4007 Assert(The_mission.red_alert);
4008 if(!The_mission.red_alert){
4010 if(game_do_cd_mission_check(Game_current_mission_filename)){
4011 gameseq_post_event(GS_EVENT_START_GAME);
4013 gameseq_post_event(GS_EVENT_MAIN_MENU);
4018 // choose the previous mission
4019 mission_campaign_previous_mission();
4021 if(game_do_cd_mission_check(Game_current_mission_filename)){
4022 gameseq_post_event(GS_EVENT_START_GAME);
4024 gameseq_post_event(GS_EVENT_MAIN_MENU);
4035 case POPUPDEAD_DO_MAIN_HALL:
4036 multi_quit_game(PROMPT_NONE,-1);
4039 case POPUPDEAD_DO_RESPAWN:
4040 multi_respawn_normal();
4041 event_music_player_respawn();
4044 case POPUPDEAD_DO_OBSERVER:
4045 multi_respawn_observer();
4046 event_music_player_respawn_as_observer();
4055 if ( leave_popup ) {
4061 // returns true if player is actually in a game_play stats
4062 int game_actually_playing()
4066 state = gameseq_get_state();
4067 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4073 // Draw the 2D HUD gauges
4074 void game_render_hud_2d()
4076 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4080 HUD_render_2d(flFrametime);
4084 // Draw the 3D-dependant HUD gauges
4085 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4087 g3_start_frame(0); // 0 = turn zbuffering off
4088 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4090 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4091 HUD_render_3d(flFrametime);
4095 game_sunspot_process(flFrametime);
4097 // Diminish the palette effect
4098 game_flash_diminish(flFrametime);
4106 int actually_playing;
4107 fix total_time1, total_time2;
4108 fix render2_time1=0, render2_time2=0;
4109 fix render3_time1=0, render3_time2=0;
4110 fix flip_time1=0, flip_time2=0;
4111 fix clear_time1=0, clear_time2=0;
4117 if (Framerate_delay) {
4118 int start_time = timer_get_milliseconds();
4119 while (timer_get_milliseconds() < start_time + Framerate_delay)
4125 demo_do_frame_start();
4127 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4132 // start timing frame
4133 timing_frame_start();
4135 total_time1 = timer_get_fixed_seconds();
4137 // var to hold which state we are in
4138 actually_playing = game_actually_playing();
4140 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4141 if (!(Game_mode & GM_STANDALONE_SERVER)){
4142 Assert( OBJ_INDEX(Player_obj) >= 0 );
4146 if (Missiontime > Entry_delay_time){
4147 Pre_player_entry = 0;
4149 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4152 // Note: These are done even before the player enters, else buffers can overflow.
4153 if (! (Game_mode & GM_STANDALONE_SERVER)){
4157 shield_frame_init();
4159 if ( Player->control_mode != PCM_NORMAL )
4162 if ( !Pre_player_entry && actually_playing ) {
4163 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4165 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4166 game_process_keys();
4168 // don't read flying controls if we're playing a demo back
4169 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4170 read_player_controls( Player_obj, flFrametime);
4174 // if we're not the master, we may have to send the server-critical ship status button_info bits
4175 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4176 multi_maybe_send_ship_status();
4181 // Reset the whack stuff
4184 // These two lines must be outside of Pre_player_entry code,
4185 // otherwise too many lights are added.
4188 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4192 game_simulation_frame();
4194 // if not actually in a game play state, then return. This condition could only be true in
4195 // a multiplayer game.
4196 if ( !actually_playing ) {
4197 Assert( Game_mode & GM_MULTIPLAYER );
4201 if (!Pre_player_entry) {
4202 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4203 clear_time1 = timer_get_fixed_seconds();
4204 // clear the screen to black
4206 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4210 clear_time2 = timer_get_fixed_seconds();
4211 render3_time1 = timer_get_fixed_seconds();
4212 game_render_frame_setup(&eye_pos, &eye_orient);
4213 game_render_frame( &eye_pos, &eye_orient );
4215 // save the eye position and orientation
4216 if ( Game_mode & GM_MULTIPLAYER ) {
4217 Net_player->s_info.eye_pos = eye_pos;
4218 Net_player->s_info.eye_orient = eye_orient;
4221 hud_show_target_model();
4223 // check to see if we should display the death died popup
4224 if(Game_mode & GM_DEAD_BLEW_UP){
4225 if(Game_mode & GM_MULTIPLAYER){
4226 // catch the situation where we're supposed to be warping out on this transition
4227 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4228 gameseq_post_event(GS_EVENT_DEBRIEF);
4229 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4230 Player_died_popup_wait = -1;
4234 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4235 Player_died_popup_wait = -1;
4241 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4242 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4243 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4244 if(!popupdead_is_active()){
4248 Player_multi_died_check = -1;
4252 render3_time2 = timer_get_fixed_seconds();
4253 render2_time1 = timer_get_fixed_seconds();
4256 game_get_framerate();
4257 game_show_framerate();
4259 game_show_time_left();
4261 // Draw the 2D HUD gauges
4262 if(supernova_active() < 3){
4263 game_render_hud_2d();
4266 game_set_view_clip();
4268 // Draw 3D HUD gauges
4269 game_render_hud_3d(&eye_pos, &eye_orient);
4273 render2_time2 = timer_get_fixed_seconds();
4275 // maybe render and process the dead popup
4276 game_maybe_do_dead_popup(flFrametime);
4278 // start timing frame
4279 timing_frame_stop();
4280 // timing_display(30, 10);
4282 // If a regular popup is active, don't flip (popup code flips)
4283 if( !popup_running_state() ){
4284 flip_time1 = timer_get_fixed_seconds();
4285 game_flip_page_and_time_it();
4286 flip_time2 = timer_get_fixed_seconds();
4290 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4293 game_show_standalone_framerate();
4297 game_do_training_checks();
4300 // process lightning (nebula only)
4303 total_time2 = timer_get_fixed_seconds();
4305 // Got some timing numbers
4306 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4307 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4308 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4309 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4310 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4313 demo_do_frame_end();
4315 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4321 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4322 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4323 // died. This resulted in screwed up death sequences.
4325 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4326 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4327 static int timer_paused=0;
4328 static int stop_count,start_count;
4329 static int time_stopped,time_started;
4330 int saved_timestamp_ticker = -1;
4332 void game_reset_time()
4334 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4338 // Last_time = timer_get_fixed_seconds();
4344 void game_stop_time()
4346 if (timer_paused==0) {
4348 time = timer_get_fixed_seconds();
4349 // Save how much time progressed so far in the frame so we can
4350 // use it when we unpause.
4351 Last_delta_time = time - Last_time;
4353 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4354 if (Last_delta_time < 0) {
4355 #if defined(TIMER_TEST) && !defined(NDEBUG)
4356 Int3(); //get Matt!!!!
4358 Last_delta_time = 0;
4360 #if defined(TIMER_TEST) && !defined(NDEBUG)
4361 time_stopped = time;
4364 // Stop the timer_tick stuff...
4365 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4366 saved_timestamp_ticker = timestamp_ticker;
4370 #if defined(TIMER_TEST) && !defined(NDEBUG)
4375 void game_start_time()
4378 Assert(timer_paused >= 0);
4379 if (timer_paused==0) {
4381 time = timer_get_fixed_seconds();
4382 #if defined(TIMER_TEST) && !defined(NDEBUG)
4384 Int3(); //get Matt!!!!
4387 // Take current time, and set it backwards to account for time
4388 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4389 // will be correct when it goes to calculate the frametime next
4391 Last_time = time - Last_delta_time;
4392 #if defined(TIMER_TEST) && !defined(NDEBUG)
4393 time_started = time;
4396 // Restore the timer_tick stuff...
4397 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4398 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4399 timestamp_ticker = saved_timestamp_ticker;
4400 saved_timestamp_ticker = -1;
4403 #if defined(TIMER_TEST) && !defined(NDEBUG)
4409 void game_set_frametime(int state)
4412 float frame_cap_diff;
4414 thistime = timer_get_fixed_seconds();
4416 if ( Last_time == 0 )
4417 Frametime = F1_0 / 30;
4419 Frametime = thistime - Last_time;
4421 // Frametime = F1_0 / 30;
4423 fix debug_frametime = Frametime; // Just used to display frametime.
4425 // If player hasn't entered mission yet, make frame take 1/4 second.
4426 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4429 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4431 fix frame_speed = F1_0 / Debug_dump_frames;
4433 if (Frametime > frame_speed ){
4434 nprintf(("warning","slow frame: %x\n",Frametime));
4437 thistime = timer_get_fixed_seconds();
4438 Frametime = thistime - Last_time;
4439 } while (Frametime < frame_speed );
4441 Frametime = frame_speed;
4445 Assert( Framerate_cap > 0 );
4447 // Cap the framerate so it doesn't get too high.
4451 cap = F1_0/Framerate_cap;
4452 if (Frametime < cap) {
4453 thistime = cap - Frametime;
4454 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4455 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4457 thistime = timer_get_fixed_seconds();
4461 if((Game_mode & GM_STANDALONE_SERVER) &&
4462 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4464 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4465 Sleep((DWORD)(frame_cap_diff*1000));
4467 thistime += fl2f((frame_cap_diff));
4469 Frametime = thistime - Last_time;
4472 // If framerate is too low, cap it.
4473 if (Frametime > MAX_FRAMETIME) {
4475 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4477 // to remove warnings in release build
4478 debug_frametime = fl2f(flFrametime);
4480 Frametime = MAX_FRAMETIME;
4483 Frametime = fixmul(Frametime, Game_time_compression);
4485 Last_time = thistime;
4486 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4488 flFrametime = f2fl(Frametime);
4489 //if(!(Game_mode & GM_PLAYING_DEMO)){
4490 timestamp_inc(flFrametime);
4492 /* if ((Framecount > 0) && (Framecount < 10)) {
4493 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4498 // This is called from game_do_frame(), and from navmap_do_frame()
4499 void game_update_missiontime()
4501 // TODO JAS: Put in if and move this into game_set_frametime,
4502 // fix navmap to call game_stop/start_time
4503 //if ( !timer_paused )
4504 Missiontime += Frametime;
4507 void game_do_frame()
4509 game_set_frametime(GS_STATE_GAME_PLAY);
4510 game_update_missiontime();
4512 if (Game_mode & GM_STANDALONE_SERVER) {
4513 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4516 if ( game_single_step && (last_single_step == game_single_step) ) {
4517 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4518 while( key_checkch() == 0 )
4520 os_set_title( XSTR( "FreeSpace", 171) );
4521 Last_time = timer_get_fixed_seconds();
4524 last_single_step = game_single_step;
4526 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4527 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4531 Keep_mouse_centered = 0;
4532 monitor_update(); // Update monitor variables
4535 void multi_maybe_do_frame()
4537 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4542 int Joymouse_button_status = 0;
4544 // Flush all input devices
4552 Joymouse_button_status = 0;
4554 //mprintf(("Game flush!\n" ));
4557 // function for multiplayer only which calls game_do_state_common() when running the
4559 void game_do_dc_networking()
4561 Assert( Game_mode & GM_MULTIPLAYER );
4563 game_do_state_common( gameseq_get_state() );
4566 // Call this whenever in a loop, or when you need to check for a keystroke.
4567 int game_check_key()
4573 // convert keypad enter to normal enter
4574 if ((k & KEY_MASK) == KEY_PADENTER)
4575 k = (k & ~KEY_MASK) | KEY_ENTER;
4582 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4583 static int Demo_show_trailer_timestamp = 0;
4585 void demo_reset_trailer_timer()
4587 Demo_show_trailer_timestamp = timer_get_milliseconds();
4590 void demo_maybe_show_trailer(int k)
4593 // if key pressed, reset demo trailer timer
4595 demo_reset_trailer_timer();
4599 // if mouse moved, reset demo trailer timer
4602 mouse_get_delta(&dx, &dy);
4603 if ( (dx > 0) || (dy > 0) ) {
4604 demo_reset_trailer_timer();
4608 // if joystick has moved, reset demo trailer timer
4611 joy_get_delta(&dx, &dy);
4612 if ( (dx > 0) || (dy > 0) ) {
4613 demo_reset_trailer_timer();
4617 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4618 // the low-level code. Ugly, I know... but was the simplest and most
4621 // if 30 seconds since last demo trailer time reset, launch movie
4622 if ( os_foreground() ) {
4623 int now = timer_get_milliseconds();
4624 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4625 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4627 movie_play( NOX("fstrailer2.mve") );
4628 demo_reset_trailer_timer();
4636 // same as game_check_key(), except this is used while actually in the game. Since there
4637 // generally are differences between game control keys and general UI keys, makes sense to
4638 // have seperate functions for each case. If you are not checking a game control while in a
4639 // mission, you should probably be using game_check_key() instead.
4644 if (!os_foreground()) {
4649 // If we're in a single player game, pause it.
4650 if (!(Game_mode & GM_MULTIPLAYER)){
4651 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4652 game_process_pause_key();
4660 demo_maybe_show_trailer(k);
4663 // Move the mouse cursor with the joystick.
4664 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4665 // Move the mouse cursor with the joystick
4669 joy_get_pos( &jx, &jy, &jz, &jr );
4671 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4672 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4675 mouse_get_real_pos( &mx, &my );
4676 mouse_set_pos( mx+dx, my+dy );
4681 m = mouse_down(MOUSE_LEFT_BUTTON);
4683 if ( j != Joymouse_button_status ) {
4684 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4685 Joymouse_button_status = j;
4687 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4688 } else if ( (!j) && (m) ) {
4689 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4694 // if we should be ignoring keys because of some multiplayer situations
4695 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4699 // If a popup is running, don't process all the Fn keys
4700 if( popup_active() ) {
4704 state = gameseq_get_state();
4706 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4709 case KEY_DEBUGGED + KEY_BACKSP:
4714 launch_context_help();
4719 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4721 // don't allow f2 while warping out in multiplayer
4722 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4727 case GS_STATE_INITIAL_PLAYER_SELECT:
4728 case GS_STATE_OPTIONS_MENU:
4729 case GS_STATE_HUD_CONFIG:
4730 case GS_STATE_CONTROL_CONFIG:
4731 case GS_STATE_DEATH_DIED:
4732 case GS_STATE_DEATH_BLEW_UP:
4733 case GS_STATE_VIEW_MEDALS:
4737 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4744 // hotkey selection screen -- only valid from briefing and beyond.
4747 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) ) {
4748 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4754 case KEY_DEBUGGED + KEY_F3:
4755 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4758 case KEY_DEBUGGED + KEY_F4:
4759 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4763 if(Game_mode & GM_MULTIPLAYER){
4764 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4765 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4769 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4770 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4776 case KEY_ESC | KEY_SHIFTED:
4777 // make sure to quit properly out of multiplayer
4778 if(Game_mode & GM_MULTIPLAYER){
4779 multi_quit_game(PROMPT_NONE);
4782 gameseq_post_event( GS_EVENT_QUIT_GAME );
4787 case KEY_DEBUGGED + KEY_P:
4790 case KEY_PRINT_SCRN:
4792 static int counter = 0;
4797 sprintf( tmp_name, NOX("screen%02d"), counter );
4799 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4800 gr_print_screen(tmp_name);
4808 case KEY_SHIFTED | KEY_ENTER: {
4810 #if !defined(NDEBUG)
4812 if ( Game_mode & GM_NORMAL ){
4816 // if we're in multiplayer mode, do some special networking
4817 if(Game_mode & GM_MULTIPLAYER){
4818 debug_console(game_do_dc_networking);
4825 if ( Game_mode & GM_NORMAL )
4839 gameseq_post_event(GS_EVENT_QUIT_GAME);
4842 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4845 void camera_set_position( vector *pos )
4850 void camera_set_orient( matrix *orient )
4852 Camera_orient = *orient;
4855 void camera_set_velocity( vector *vel, int instantaneous )
4857 Camera_desired_velocity.x = 0.0f;
4858 Camera_desired_velocity.y = 0.0f;
4859 Camera_desired_velocity.z = 0.0f;
4861 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4862 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4863 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4865 if ( instantaneous ) {
4866 Camera_velocity = Camera_desired_velocity;
4874 vector new_vel, delta_pos;
4876 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4877 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4878 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4880 Camera_velocity = new_vel;
4882 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4884 vm_vec_add2( &Camera_pos, &delta_pos );
4886 float ot = Camera_time+0.0f;
4888 Camera_time += flFrametime;
4890 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4893 tmp.z = 4.739f; // always go this fast forward.
4895 // pick x and y velocities so they are always on a
4896 // circle with a 25 m radius.
4898 float tmp_angle = frand()*PI2;
4900 tmp.x = 22.0f * (float)sin(tmp_angle);
4901 tmp.y = -22.0f * (float)cos(tmp_angle);
4903 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4905 //mprintf(( "Changing velocity!\n" ));
4906 camera_set_velocity( &tmp, 0 );
4909 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4910 vector tmp = { 0.0f, 0.0f, 0.0f };
4911 camera_set_velocity( &tmp, 0 );
4916 void end_demo_campaign_do()
4918 #if defined(FS2_DEMO)
4919 // show upsell screens
4920 demo_upsell_show_screens();
4921 #elif defined(OEM_BUILD)
4922 // show oem upsell screens
4923 oem_upsell_show_screens();
4926 // drop into main hall
4927 gameseq_post_event( GS_EVENT_MAIN_MENU );
4930 // All code to process events. This is the only place
4931 // that you should change the state of the game.
4932 void game_process_event( int current_state, int event )
4934 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4937 case GS_EVENT_SIMULATOR_ROOM:
4938 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4941 case GS_EVENT_MAIN_MENU:
4942 gameseq_set_state(GS_STATE_MAIN_MENU);
4945 case GS_EVENT_OPTIONS_MENU:
4946 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4949 case GS_EVENT_BARRACKS_MENU:
4950 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4953 case GS_EVENT_TECH_MENU:
4954 gameseq_set_state(GS_STATE_TECH_MENU);
4957 case GS_EVENT_TRAINING_MENU:
4958 gameseq_set_state(GS_STATE_TRAINING_MENU);
4961 case GS_EVENT_START_GAME:
4962 Select_default_ship = 0;
4963 Player_multi_died_check = -1;
4964 gameseq_set_state(GS_STATE_CMD_BRIEF);
4967 case GS_EVENT_START_BRIEFING:
4968 gameseq_set_state(GS_STATE_BRIEFING);
4971 case GS_EVENT_DEBRIEF:
4972 // did we end the campaign in the main freespace 2 single player campaign?
4973 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4974 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4976 gameseq_set_state(GS_STATE_DEBRIEF);
4979 Player_multi_died_check = -1;
4982 case GS_EVENT_SHIP_SELECTION:
4983 gameseq_set_state( GS_STATE_SHIP_SELECT );
4986 case GS_EVENT_WEAPON_SELECTION:
4987 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4990 case GS_EVENT_ENTER_GAME:
4992 // maybe start recording a demo
4994 demo_start_record("test.fsd");
4998 if (Game_mode & GM_MULTIPLAYER) {
4999 // if we're respawning, make sure we change the view mode so that the hud shows up
5000 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5004 gameseq_set_state(GS_STATE_GAME_PLAY);
5006 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5009 Player_multi_died_check = -1;
5011 // clear multiplayer button info
5012 extern button_info Multi_ship_status_bi;
5013 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5015 Start_time = f2fl(timer_get_approx_seconds());
5017 mprintf(("Entering game at time = %7.3f\n", Start_time));
5021 case GS_EVENT_START_GAME_QUICK:
5022 Select_default_ship = 1;
5023 gameseq_post_event(GS_EVENT_ENTER_GAME);
5027 case GS_EVENT_END_GAME:
5028 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5029 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5030 gameseq_set_state(GS_STATE_MAIN_MENU);
5035 Player_multi_died_check = -1;
5038 case GS_EVENT_QUIT_GAME:
5039 main_hall_stop_music();
5040 main_hall_stop_ambient();
5041 gameseq_set_state(GS_STATE_QUIT_GAME);
5043 Player_multi_died_check = -1;
5046 case GS_EVENT_GAMEPLAY_HELP:
5047 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5050 case GS_EVENT_PAUSE_GAME:
5051 gameseq_push_state(GS_STATE_GAME_PAUSED);
5054 case GS_EVENT_DEBUG_PAUSE_GAME:
5055 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5058 case GS_EVENT_TRAINING_PAUSE:
5059 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5062 case GS_EVENT_PREVIOUS_STATE:
5063 gameseq_pop_state();
5066 case GS_EVENT_TOGGLE_FULLSCREEN:
5067 #ifndef HARDWARE_ONLY
5069 if ( gr_screen.mode == GR_SOFTWARE ) {
5070 gr_init( GR_640, GR_DIRECTDRAW );
5071 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5072 gr_init( GR_640, GR_SOFTWARE );
5078 case GS_EVENT_TOGGLE_GLIDE:
5080 if ( gr_screen.mode != GR_GLIDE ) {
5081 gr_init( GR_640, GR_GLIDE );
5083 gr_init( GR_640, GR_SOFTWARE );
5088 case GS_EVENT_LOAD_MISSION_MENU:
5089 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5092 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5093 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5096 case GS_EVENT_HUD_CONFIG:
5097 gameseq_push_state( GS_STATE_HUD_CONFIG );
5100 case GS_EVENT_CONTROL_CONFIG:
5101 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5104 case GS_EVENT_DEATH_DIED:
5105 gameseq_set_state( GS_STATE_DEATH_DIED );
5108 case GS_EVENT_DEATH_BLEW_UP:
5109 if ( current_state == GS_STATE_DEATH_DIED ) {
5110 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5111 event_music_player_death();
5113 // multiplayer clients set their extra check here
5114 if(Game_mode & GM_MULTIPLAYER){
5115 // set the multi died absolute last chance check
5116 Player_multi_died_check = time(NULL);
5119 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5123 case GS_EVENT_NEW_CAMPAIGN:
5124 if (!mission_load_up_campaign()){
5125 readyroom_continue_campaign();
5128 Player_multi_died_check = -1;
5131 case GS_EVENT_CAMPAIGN_CHEAT:
5132 if (!mission_load_up_campaign()){
5134 // bash campaign value
5135 extern char Main_hall_campaign_cheat[512];
5138 // look for the mission
5139 for(idx=0; idx<Campaign.num_missions; idx++){
5140 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5141 Campaign.next_mission = idx;
5142 Campaign.prev_mission = idx - 1;
5149 readyroom_continue_campaign();
5152 Player_multi_died_check = -1;
5155 case GS_EVENT_CAMPAIGN_ROOM:
5156 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5159 case GS_EVENT_CMD_BRIEF:
5160 gameseq_set_state(GS_STATE_CMD_BRIEF);
5163 case GS_EVENT_RED_ALERT:
5164 gameseq_set_state(GS_STATE_RED_ALERT);
5167 case GS_EVENT_CREDITS:
5168 gameseq_set_state( GS_STATE_CREDITS );
5171 case GS_EVENT_VIEW_MEDALS:
5172 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5175 case GS_EVENT_SHOW_GOALS:
5176 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5179 case GS_EVENT_HOTKEY_SCREEN:
5180 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5183 // multiplayer stuff follow these comments
5185 case GS_EVENT_MULTI_JOIN_GAME:
5186 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5189 case GS_EVENT_MULTI_HOST_SETUP:
5190 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5193 case GS_EVENT_MULTI_CLIENT_SETUP:
5194 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5197 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5198 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5201 case GS_EVENT_MULTI_STD_WAIT:
5202 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5205 case GS_EVENT_STANDALONE_MAIN:
5206 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5209 case GS_EVENT_MULTI_PAUSE:
5210 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5213 case GS_EVENT_INGAME_PRE_JOIN:
5214 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5217 case GS_EVENT_EVENT_DEBUG:
5218 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5221 // Start a warpout where player automatically goes 70 no matter what
5222 // and can't cancel out of it.
5223 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5224 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5226 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5227 Player->saved_viewer_mode = Viewer_mode;
5228 Player->control_mode = PCM_WARPOUT_STAGE1;
5229 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5230 Warpout_time = 0.0f; // Start timer!
5233 case GS_EVENT_PLAYER_WARPOUT_START:
5234 if ( Player->control_mode != PCM_NORMAL ) {
5235 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5237 Player->saved_viewer_mode = Viewer_mode;
5238 Player->control_mode = PCM_WARPOUT_STAGE1;
5239 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5240 Warpout_time = 0.0f; // Start timer!
5241 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5245 case GS_EVENT_PLAYER_WARPOUT_STOP:
5246 if ( Player->control_mode != PCM_NORMAL ) {
5247 if ( !Warpout_forced ) { // cannot cancel forced warpout
5248 Player->control_mode = PCM_NORMAL;
5249 Viewer_mode = Player->saved_viewer_mode;
5250 hud_subspace_notify_abort();
5251 mprintf(( "Player put back to normal mode.\n" ));
5252 if ( Warpout_sound > -1 ) {
5253 snd_stop( Warpout_sound );
5260 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5261 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5262 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5263 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5265 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5266 shipfx_warpout_start( Player_obj );
5267 Player->control_mode = PCM_WARPOUT_STAGE2;
5268 Player->saved_viewer_mode = Viewer_mode;
5269 Viewer_mode |= VM_WARP_CHASE;
5271 vector tmp = Player_obj->pos;
5273 ship_get_eye( &tmp, &tmp_m, Player_obj );
5274 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5275 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5276 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5278 camera_set_position( &tmp );
5279 camera_set_orient( &Player_obj->orient );
5280 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5282 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5283 camera_set_velocity( &tmp_vel, 1);
5287 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5288 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5289 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5290 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5292 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5293 Player->control_mode = PCM_WARPOUT_STAGE3;
5297 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5298 mprintf(( "Player warped out. Going to debriefing!\n" ));
5299 Player->control_mode = PCM_NORMAL;
5300 Viewer_mode = Player->saved_viewer_mode;
5303 // we have a special debriefing screen for multiplayer furballs
5304 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5305 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5307 // do the normal debriefing for all other situations
5309 gameseq_post_event(GS_EVENT_DEBRIEF);
5313 case GS_EVENT_STANDALONE_POSTGAME:
5314 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5317 case GS_EVENT_INITIAL_PLAYER_SELECT:
5318 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5321 case GS_EVENT_GAME_INIT:
5322 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5323 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5325 // see if the command line option has been set to use the last pilot, and act acoordingly
5326 if( player_select_get_last_pilot() ) {
5327 // always enter the main menu -- do the automatic network startup stuff elsewhere
5328 // so that we still have valid checks for networking modes, etc.
5329 gameseq_set_state(GS_STATE_MAIN_MENU);
5331 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5336 case GS_EVENT_MULTI_MISSION_SYNC:
5337 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5340 case GS_EVENT_MULTI_START_GAME:
5341 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5344 case GS_EVENT_MULTI_HOST_OPTIONS:
5345 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5348 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5349 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5352 case GS_EVENT_TEAM_SELECT:
5353 gameseq_set_state(GS_STATE_TEAM_SELECT);
5356 case GS_EVENT_END_CAMPAIGN:
5357 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5360 case GS_EVENT_END_DEMO:
5361 gameseq_set_state(GS_STATE_END_DEMO);
5364 case GS_EVENT_LOOP_BRIEF:
5365 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5374 // Called when a state is being left.
5375 // The current state is still at old_state, but as soon as
5376 // this function leaves, then the current state will become
5377 // new state. You should never try to change the state
5378 // in here... if you think you need to, you probably really
5379 // need to post an event, not change the state.
5380 void game_leave_state( int old_state, int new_state )
5382 int end_mission = 1;
5384 switch (new_state) {
5385 case GS_STATE_GAME_PAUSED:
5386 case GS_STATE_DEBUG_PAUSED:
5387 case GS_STATE_OPTIONS_MENU:
5388 case GS_STATE_CONTROL_CONFIG:
5389 case GS_STATE_MISSION_LOG_SCROLLBACK:
5390 case GS_STATE_DEATH_DIED:
5391 case GS_STATE_SHOW_GOALS:
5392 case GS_STATE_HOTKEY_SCREEN:
5393 case GS_STATE_MULTI_PAUSED:
5394 case GS_STATE_TRAINING_PAUSED:
5395 case GS_STATE_EVENT_DEBUG:
5396 case GS_STATE_GAMEPLAY_HELP:
5397 end_mission = 0; // these events shouldn't end a mission
5401 switch (old_state) {
5402 case GS_STATE_BRIEFING:
5403 brief_stop_voices();
5404 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5405 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5406 && (new_state != GS_STATE_TEAM_SELECT) ){
5407 common_select_close();
5408 if ( new_state == GS_STATE_MAIN_MENU ) {
5409 freespace_stop_mission();
5413 // COMMAND LINE OPTION
5414 if (Cmdline_multi_stream_chat_to_file){
5415 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5416 cfclose(Multi_chat_stream);
5420 case GS_STATE_DEBRIEF:
5421 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5426 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5427 multi_df_debrief_close();
5430 case GS_STATE_LOAD_MISSION_MENU:
5431 mission_load_menu_close();
5434 case GS_STATE_SIMULATOR_ROOM:
5438 case GS_STATE_CAMPAIGN_ROOM:
5439 campaign_room_close();
5442 case GS_STATE_CMD_BRIEF:
5443 if (new_state == GS_STATE_OPTIONS_MENU) {
5448 if (new_state == GS_STATE_MAIN_MENU)
5449 freespace_stop_mission();
5454 case GS_STATE_RED_ALERT:
5458 case GS_STATE_SHIP_SELECT:
5459 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5460 new_state != GS_STATE_HOTKEY_SCREEN &&
5461 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5462 common_select_close();
5463 if ( new_state == GS_STATE_MAIN_MENU ) {
5464 freespace_stop_mission();
5469 case GS_STATE_WEAPON_SELECT:
5470 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5471 new_state != GS_STATE_HOTKEY_SCREEN &&
5472 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5473 common_select_close();
5474 if ( new_state == GS_STATE_MAIN_MENU ) {
5475 freespace_stop_mission();
5480 case GS_STATE_TEAM_SELECT:
5481 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5482 new_state != GS_STATE_HOTKEY_SCREEN &&
5483 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5484 common_select_close();
5485 if ( new_state == GS_STATE_MAIN_MENU ) {
5486 freespace_stop_mission();
5491 case GS_STATE_MAIN_MENU:
5492 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5499 case GS_STATE_OPTIONS_MENU:
5500 //game_start_time();
5501 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5502 multi_join_clear_game_list();
5504 options_menu_close();
5507 case GS_STATE_BARRACKS_MENU:
5508 if(new_state != GS_STATE_VIEW_MEDALS){
5513 case GS_STATE_MISSION_LOG_SCROLLBACK:
5514 hud_scrollback_close();
5517 case GS_STATE_TRAINING_MENU:
5518 training_menu_close();
5521 case GS_STATE_GAME_PLAY:
5522 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5523 player_save_target_and_weapon_link_prefs();
5524 game_stop_looped_sounds();
5527 sound_env_disable();
5528 joy_ff_stop_effects();
5530 // stop game time under certain conditions
5531 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5536 // shut down any recording or playing demos
5541 // when in multiplayer and going back to the main menu, send a leave game packet
5542 // right away (before calling stop mission). stop_mission was taking to long to
5543 // close mission down and I want people to get notified ASAP.
5544 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5545 multi_quit_game(PROMPT_NONE);
5548 freespace_stop_mission();
5549 Game_time_compression = F1_0;
5553 case GS_STATE_TECH_MENU:
5557 case GS_STATE_TRAINING_PAUSED:
5558 Training_num_lines = 0;
5559 // fall through to GS_STATE_GAME_PAUSED
5561 case GS_STATE_GAME_PAUSED:
5563 if ( end_mission ) {
5568 case GS_STATE_DEBUG_PAUSED:
5571 pause_debug_close();
5575 case GS_STATE_HUD_CONFIG:
5579 // join/start a game
5580 case GS_STATE_MULTI_JOIN_GAME:
5581 if(new_state != GS_STATE_OPTIONS_MENU){
5582 multi_join_game_close();
5586 case GS_STATE_MULTI_HOST_SETUP:
5587 case GS_STATE_MULTI_CLIENT_SETUP:
5588 // if this is just the host going into the options screen, don't do anything
5589 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5593 // close down the proper state
5594 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5595 multi_create_game_close();
5597 multi_game_client_setup_close();
5600 // COMMAND LINE OPTION
5601 if (Cmdline_multi_stream_chat_to_file){
5602 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5603 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5604 cfclose(Multi_chat_stream);
5609 case GS_STATE_CONTROL_CONFIG:
5610 control_config_close();
5613 case GS_STATE_DEATH_DIED:
5614 Game_mode &= ~GM_DEAD_DIED;
5616 // early end while respawning or blowing up in a multiplayer game
5617 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5619 freespace_stop_mission();
5623 case GS_STATE_DEATH_BLEW_UP:
5624 Game_mode &= ~GM_DEAD_BLEW_UP;
5626 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5627 // to determine if I should do anything.
5628 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5630 freespace_stop_mission();
5633 // if we are not respawing as an observer or as a player, our new state will not
5634 // be gameplay state.
5635 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5636 game_stop_time(); // hasn't been called yet!!
5637 freespace_stop_mission();
5643 case GS_STATE_CREDITS:
5647 case GS_STATE_VIEW_MEDALS:
5651 case GS_STATE_SHOW_GOALS:
5652 mission_show_goals_close();
5655 case GS_STATE_HOTKEY_SCREEN:
5656 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5657 mission_hotkey_close();
5661 case GS_STATE_MULTI_MISSION_SYNC:
5662 // if we're moving into the options menu, don't do anything
5663 if(new_state == GS_STATE_OPTIONS_MENU){
5667 Assert( Game_mode & GM_MULTIPLAYER );
5669 if ( new_state == GS_STATE_GAME_PLAY ){
5670 // palette_restore_palette();
5672 // change a couple of flags to indicate our state!!!
5673 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5674 send_netplayer_update_packet();
5676 // set the game mode
5677 Game_mode |= GM_IN_MISSION;
5681 case GS_STATE_VIEW_CUTSCENES:
5682 cutscenes_screen_close();
5685 case GS_STATE_MULTI_STD_WAIT:
5686 multi_standalone_wait_close();
5689 case GS_STATE_STANDALONE_MAIN:
5690 standalone_main_close();
5691 if(new_state == GS_STATE_MULTI_STD_WAIT){
5692 init_multiplayer_stats();
5696 case GS_STATE_MULTI_PAUSED:
5697 // if ( end_mission ){
5702 case GS_STATE_INGAME_PRE_JOIN:
5703 multi_ingame_select_close();
5706 case GS_STATE_STANDALONE_POSTGAME:
5707 multi_standalone_postgame_close();
5710 case GS_STATE_INITIAL_PLAYER_SELECT:
5711 player_select_close();
5714 case GS_STATE_MULTI_START_GAME:
5715 multi_start_game_close();
5718 case GS_STATE_MULTI_HOST_OPTIONS:
5719 multi_host_options_close();
5722 case GS_STATE_END_OF_CAMPAIGN:
5723 mission_campaign_end_close();
5726 case GS_STATE_LOOP_BRIEF:
5732 // Called when a state is being entered.
5733 // The current state is set to the state we're entering at
5734 // this point, and old_state is set to the state we're coming
5735 // from. You should never try to change the state
5736 // in here... if you think you need to, you probably really
5737 // need to post an event, not change the state.
5739 void game_enter_state( int old_state, int new_state )
5741 switch (new_state) {
5742 case GS_STATE_MAIN_MENU:
5743 // in multiplayer mode, be sure that we are not doing networking anymore.
5744 if ( Game_mode & GM_MULTIPLAYER ) {
5745 Assert( Net_player != NULL );
5746 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5749 Game_time_compression = F1_0;
5751 // determine which ship this guy is currently based on
5752 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5755 if (Player->on_bastion) {
5763 case GS_STATE_BRIEFING:
5764 main_hall_stop_music();
5765 main_hall_stop_ambient();
5767 if (Game_mode & GM_NORMAL) {
5768 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5769 // MWA: or from options or hotkey screens
5770 // JH: or if the command brief state already did this
5771 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5772 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5773 && (old_state != GS_STATE_CMD_BRIEF) ) {
5774 if ( !game_start_mission() ) // this should put us into a new state on failure!
5778 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5779 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5780 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5782 Game_time_compression = F1_0;
5784 if ( red_alert_mission() ) {
5785 gameseq_post_event(GS_EVENT_RED_ALERT);
5792 case GS_STATE_DEBRIEF:
5793 game_stop_looped_sounds();
5794 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5795 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5800 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5801 multi_df_debrief_init();
5804 case GS_STATE_LOAD_MISSION_MENU:
5805 mission_load_menu_init();
5808 case GS_STATE_SIMULATOR_ROOM:
5812 case GS_STATE_CAMPAIGN_ROOM:
5813 campaign_room_init();
5816 case GS_STATE_RED_ALERT:
5817 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5821 case GS_STATE_CMD_BRIEF: {
5822 int team_num = 0; // team number used as index for which cmd brief to use.
5824 if (old_state == GS_STATE_OPTIONS_MENU) {
5828 main_hall_stop_music();
5829 main_hall_stop_ambient();
5831 if (Game_mode & GM_NORMAL) {
5832 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5833 // MWA: or from options or hotkey screens
5834 // JH: or if the command brief state already did this
5835 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5836 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5837 if ( !game_start_mission() ) // this should put us into a new state on failure!
5842 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5843 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5844 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5846 cmd_brief_init(team_num);
5852 case GS_STATE_SHIP_SELECT:
5856 case GS_STATE_WEAPON_SELECT:
5857 weapon_select_init();
5860 case GS_STATE_TEAM_SELECT:
5864 case GS_STATE_GAME_PAUSED:
5869 case GS_STATE_DEBUG_PAUSED:
5870 // game_stop_time();
5871 // os_set_title("FreeSpace - PAUSED");
5874 case GS_STATE_TRAINING_PAUSED:
5881 case GS_STATE_OPTIONS_MENU:
5883 options_menu_init();
5886 case GS_STATE_GAME_PLAY:
5887 // coming from the gameplay state or the main menu, we might need to load the mission
5888 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5889 if ( !game_start_mission() ) // this should put us into a new state.
5894 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5895 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5896 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5897 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5898 (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) ) {
5899 // JAS: Used to do all paging here.
5903 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5907 main_hall_stop_music();
5908 main_hall_stop_ambient();
5909 event_music_first_pattern(); // start the first pattern
5912 // special code that restores player ship selection and weapons loadout when doing a quick start
5913 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5914 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5915 wss_direct_restore_loadout();
5919 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5920 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5921 event_music_first_pattern(); // start the first pattern
5924 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5925 event_music_first_pattern(); // start the first pattern
5927 player_restore_target_and_weapon_link_prefs();
5929 Game_mode |= GM_IN_MISSION;
5932 // required to truely make mouse deltas zeroed in debug mouse code
5933 void mouse_force_pos(int x, int y);
5934 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5939 // only start time if in single player, or coming from multi wait state
5942 (Game_mode & GM_NORMAL) &&
5943 (old_state != GS_STATE_VIEW_CUTSCENES)
5945 (Game_mode & GM_MULTIPLAYER) && (
5946 (old_state == GS_STATE_MULTI_PAUSED) ||
5947 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5953 // when coming from the multi paused state, reset the timestamps
5954 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5955 multi_reset_timestamps();
5958 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5959 // initialize all object update details
5960 multi_oo_gameplay_init();
5963 // under certain circumstances, the server should reset the object update rate limiting stuff
5964 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5965 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5967 // reinitialize the rate limiting system for all clients
5968 multi_oo_rate_init_all();
5971 // multiplayer clients should always re-initialize their control info rate limiting system
5972 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5973 multi_oo_rate_init_all();
5977 if(Game_mode & GM_MULTIPLAYER){
5978 multi_ping_reset_players();
5981 Game_subspace_effect = 0;
5982 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5983 Game_subspace_effect = 1;
5984 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5985 game_start_subspace_ambient_sound();
5989 sound_env_set(&Game_sound_env);
5990 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5992 // clear multiplayer button info i
5993 extern button_info Multi_ship_status_bi;
5994 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5997 case GS_STATE_HUD_CONFIG:
6001 case GS_STATE_MULTI_JOIN_GAME:
6002 multi_join_clear_game_list();
6004 if (old_state != GS_STATE_OPTIONS_MENU) {
6005 multi_join_game_init();
6010 case GS_STATE_MULTI_HOST_SETUP:
6011 // don't reinitialize if we're coming back from the host options screen
6012 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6013 multi_create_game_init();
6018 case GS_STATE_MULTI_CLIENT_SETUP:
6019 if (old_state != GS_STATE_OPTIONS_MENU) {
6020 multi_game_client_setup_init();
6025 case GS_STATE_CONTROL_CONFIG:
6026 control_config_init();
6029 case GS_STATE_TECH_MENU:
6033 case GS_STATE_BARRACKS_MENU:
6034 if(old_state != GS_STATE_VIEW_MEDALS){
6039 case GS_STATE_MISSION_LOG_SCROLLBACK:
6040 hud_scrollback_init();
6043 case GS_STATE_DEATH_DIED:
6044 Player_died_time = timestamp(10);
6046 if(!(Game_mode & GM_MULTIPLAYER)){
6047 player_show_death_message();
6049 Game_mode |= GM_DEAD_DIED;
6052 case GS_STATE_DEATH_BLEW_UP:
6053 if ( !popupdead_is_active() ) {
6054 Player_ai->target_objnum = -1;
6057 // stop any local EMP effect
6060 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6061 Game_mode |= GM_DEAD_BLEW_UP;
6062 Show_viewing_from_self = 0;
6064 // timestamp how long we should wait before displaying the died popup
6065 if ( !popupdead_is_active() ) {
6066 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6070 case GS_STATE_GAMEPLAY_HELP:
6071 gameplay_help_init();
6074 case GS_STATE_CREDITS:
6075 main_hall_stop_music();
6076 main_hall_stop_ambient();
6080 case GS_STATE_VIEW_MEDALS:
6081 medal_main_init(Player);
6084 case GS_STATE_SHOW_GOALS:
6085 mission_show_goals_init();
6088 case GS_STATE_HOTKEY_SCREEN:
6089 mission_hotkey_init();
6092 case GS_STATE_MULTI_MISSION_SYNC:
6093 // if we're coming from the options screen, don't do any
6094 if(old_state == GS_STATE_OPTIONS_MENU){
6098 switch(Multi_sync_mode){
6099 case MULTI_SYNC_PRE_BRIEFING:
6100 // if moving from game forming to the team select state
6103 case MULTI_SYNC_POST_BRIEFING:
6104 // if moving from briefing into the mission itself
6107 // tell everyone that we're now loading data
6108 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6109 send_netplayer_update_packet();
6111 // JAS: Used to do all paging here!!!!
6113 Net_player->state = NETPLAYER_STATE_WAITING;
6114 send_netplayer_update_packet();
6116 Game_time_compression = F1_0;
6118 case MULTI_SYNC_INGAME:
6124 case GS_STATE_VIEW_CUTSCENES:
6125 cutscenes_screen_init();
6128 case GS_STATE_MULTI_STD_WAIT:
6129 multi_standalone_wait_init();
6132 case GS_STATE_STANDALONE_MAIN:
6133 // don't initialize if we're coming from one of these 2 states unless there are no
6134 // players left (reset situation)
6135 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6136 standalone_main_init();
6140 case GS_STATE_MULTI_PAUSED:
6144 case GS_STATE_INGAME_PRE_JOIN:
6145 multi_ingame_select_init();
6148 case GS_STATE_STANDALONE_POSTGAME:
6149 multi_standalone_postgame_init();
6152 case GS_STATE_INITIAL_PLAYER_SELECT:
6153 player_select_init();
6156 case GS_STATE_MULTI_START_GAME:
6157 multi_start_game_init();
6160 case GS_STATE_MULTI_HOST_OPTIONS:
6161 multi_host_options_init();
6164 case GS_STATE_END_OF_CAMPAIGN:
6165 mission_campaign_end_init();
6168 case GS_STATE_LOOP_BRIEF:
6175 // do stuff that may need to be done regardless of state
6176 void game_do_state_common(int state,int no_networking)
6178 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6179 snd_do_frame(); // update sound system
6180 event_music_do_frame(); // music needs to play across many states
6182 multi_log_process();
6184 if (no_networking) {
6188 // maybe do a multiplayer frame based on game mode and state type
6189 if (Game_mode & GM_MULTIPLAYER) {
6191 case GS_STATE_OPTIONS_MENU:
6192 case GS_STATE_GAMEPLAY_HELP:
6193 case GS_STATE_HOTKEY_SCREEN:
6194 case GS_STATE_HUD_CONFIG:
6195 case GS_STATE_CONTROL_CONFIG:
6196 case GS_STATE_MISSION_LOG_SCROLLBACK:
6197 case GS_STATE_SHOW_GOALS:
6198 case GS_STATE_VIEW_CUTSCENES:
6199 case GS_STATE_EVENT_DEBUG:
6200 multi_maybe_do_frame();
6204 game_do_networking();
6208 // Called once a frame.
6209 // You should never try to change the state
6210 // in here... if you think you need to, you probably really
6211 // need to post an event, not change the state.
6212 int Game_do_state_should_skip = 0;
6213 void game_do_state(int state)
6215 // always lets the do_state_common() function determine if the state should be skipped
6216 Game_do_state_should_skip = 0;
6218 // legal to set the should skip state anywhere in this function
6219 game_do_state_common(state); // do stuff that may need to be done regardless of state
6221 if(Game_do_state_should_skip){
6226 case GS_STATE_MAIN_MENU:
6227 game_set_frametime(GS_STATE_MAIN_MENU);
6228 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6231 main_hall_do(flFrametime);
6235 case GS_STATE_OPTIONS_MENU:
6236 game_set_frametime(GS_STATE_OPTIONS_MENU);
6237 options_menu_do_frame(flFrametime);
6240 case GS_STATE_BARRACKS_MENU:
6241 game_set_frametime(GS_STATE_BARRACKS_MENU);
6242 barracks_do_frame(flFrametime);
6245 case GS_STATE_TRAINING_MENU:
6246 game_set_frametime(GS_STATE_TRAINING_MENU);
6247 training_menu_do_frame(flFrametime);
6250 case GS_STATE_TECH_MENU:
6251 game_set_frametime(GS_STATE_TECH_MENU);
6252 techroom_do_frame(flFrametime);
6255 case GS_STATE_GAMEPLAY_HELP:
6256 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6257 gameplay_help_do_frame(flFrametime);
6260 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6264 case GS_STATE_GAME_PAUSED:
6268 case GS_STATE_DEBUG_PAUSED:
6270 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6275 case GS_STATE_TRAINING_PAUSED:
6276 game_training_pause_do();
6279 case GS_STATE_LOAD_MISSION_MENU:
6280 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6281 mission_load_menu_do();
6284 case GS_STATE_BRIEFING:
6285 game_set_frametime(GS_STATE_BRIEFING);
6286 brief_do_frame(flFrametime);
6289 case GS_STATE_DEBRIEF:
6290 game_set_frametime(GS_STATE_DEBRIEF);
6291 debrief_do_frame(flFrametime);
6294 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6295 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6296 multi_df_debrief_do();
6299 case GS_STATE_SHIP_SELECT:
6300 game_set_frametime(GS_STATE_SHIP_SELECT);
6301 ship_select_do(flFrametime);
6304 case GS_STATE_WEAPON_SELECT:
6305 game_set_frametime(GS_STATE_WEAPON_SELECT);
6306 weapon_select_do(flFrametime);
6309 case GS_STATE_MISSION_LOG_SCROLLBACK:
6310 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6311 hud_scrollback_do_frame(flFrametime);
6314 case GS_STATE_HUD_CONFIG:
6315 game_set_frametime(GS_STATE_HUD_CONFIG);
6316 hud_config_do_frame(flFrametime);
6319 case GS_STATE_MULTI_JOIN_GAME:
6320 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6321 multi_join_game_do_frame();
6324 case GS_STATE_MULTI_HOST_SETUP:
6325 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6326 multi_create_game_do();
6329 case GS_STATE_MULTI_CLIENT_SETUP:
6330 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6331 multi_game_client_setup_do_frame();
6334 case GS_STATE_CONTROL_CONFIG:
6335 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6336 control_config_do_frame(flFrametime);
6339 case GS_STATE_DEATH_DIED:
6343 case GS_STATE_DEATH_BLEW_UP:
6347 case GS_STATE_SIMULATOR_ROOM:
6348 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6349 sim_room_do_frame(flFrametime);
6352 case GS_STATE_CAMPAIGN_ROOM:
6353 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6354 campaign_room_do_frame(flFrametime);
6357 case GS_STATE_RED_ALERT:
6358 game_set_frametime(GS_STATE_RED_ALERT);
6359 red_alert_do_frame(flFrametime);
6362 case GS_STATE_CMD_BRIEF:
6363 game_set_frametime(GS_STATE_CMD_BRIEF);
6364 cmd_brief_do_frame(flFrametime);
6367 case GS_STATE_CREDITS:
6368 game_set_frametime(GS_STATE_CREDITS);
6369 credits_do_frame(flFrametime);
6372 case GS_STATE_VIEW_MEDALS:
6373 game_set_frametime(GS_STATE_VIEW_MEDALS);
6377 case GS_STATE_SHOW_GOALS:
6378 game_set_frametime(GS_STATE_SHOW_GOALS);
6379 mission_show_goals_do_frame(flFrametime);
6382 case GS_STATE_HOTKEY_SCREEN:
6383 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6384 mission_hotkey_do_frame(flFrametime);
6387 case GS_STATE_VIEW_CUTSCENES:
6388 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6389 cutscenes_screen_do_frame();
6392 case GS_STATE_MULTI_STD_WAIT:
6393 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6394 multi_standalone_wait_do();
6397 case GS_STATE_STANDALONE_MAIN:
6398 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6399 standalone_main_do();
6402 case GS_STATE_MULTI_PAUSED:
6403 game_set_frametime(GS_STATE_MULTI_PAUSED);
6407 case GS_STATE_TEAM_SELECT:
6408 game_set_frametime(GS_STATE_TEAM_SELECT);
6412 case GS_STATE_INGAME_PRE_JOIN:
6413 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6414 multi_ingame_select_do();
6417 case GS_STATE_EVENT_DEBUG:
6419 game_set_frametime(GS_STATE_EVENT_DEBUG);
6420 game_show_event_debug(flFrametime);
6424 case GS_STATE_STANDALONE_POSTGAME:
6425 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6426 multi_standalone_postgame_do();
6429 case GS_STATE_INITIAL_PLAYER_SELECT:
6430 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6434 case GS_STATE_MULTI_MISSION_SYNC:
6435 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6439 case GS_STATE_MULTI_START_GAME:
6440 game_set_frametime(GS_STATE_MULTI_START_GAME);
6441 multi_start_game_do();
6444 case GS_STATE_MULTI_HOST_OPTIONS:
6445 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6446 multi_host_options_do();
6449 case GS_STATE_END_OF_CAMPAIGN:
6450 mission_campaign_end_do();
6453 case GS_STATE_END_DEMO:
6454 game_set_frametime(GS_STATE_END_DEMO);
6455 end_demo_campaign_do();
6458 case GS_STATE_LOOP_BRIEF:
6459 game_set_frametime(GS_STATE_LOOP_BRIEF);
6463 } // end switch(gs_current_state)
6467 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6468 int game_do_ram_check(int ram_in_bytes)
6470 if ( ram_in_bytes < 30*1024*1024 ) {
6471 int allowed_to_run = 1;
6472 if ( ram_in_bytes < 25*1024*1024 ) {
6477 int Freespace_total_ram_MB;
6478 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6480 if ( allowed_to_run ) {
6482 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);
6486 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6487 if ( msgbox_rval == IDCANCEL ) {
6494 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);
6496 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6507 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6508 // If so, copy it over and remove the update directory.
6509 void game_maybe_update_launcher(char *exe_dir)
6512 char src_filename[MAX_PATH];
6513 char dest_filename[MAX_PATH];
6515 strcpy(src_filename, exe_dir);
6516 strcat(src_filename, NOX("\\update\\freespace.exe"));
6518 strcpy(dest_filename, exe_dir);
6519 strcat(dest_filename, NOX("\\freespace.exe"));
6521 // see if src_filename exists
6523 fp = fopen(src_filename, "rb");
6529 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6531 // copy updated freespace.exe to freespace exe dir
6532 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6533 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 );
6537 // delete the file in the update directory
6538 DeleteFile(src_filename);
6540 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6541 char update_dir[MAX_PATH];
6542 strcpy(update_dir, exe_dir);
6543 strcat(update_dir, NOX("\\update"));
6544 RemoveDirectory(update_dir);
6550 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6554 int sub_total_destroyed = 0;
6558 // get the total for all his children
6559 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6560 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6563 // find the # of faces for this _individual_ object
6564 total = submodel_get_num_polys(model_num, sm);
6565 if(strstr(pm->submodel[sm].name, "-destroyed")){
6566 sub_total_destroyed = total;
6570 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6573 *out_total += total + sub_total;
6574 *out_destroyed_total += sub_total_destroyed;
6577 #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);
6578 void game_spew_pof_info()
6580 char *pof_list[1000];
6583 int idx, model_num, i, j;
6585 int total, root_total, model_total, destroyed_total, counted;
6589 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6591 // spew info on all the pofs
6597 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6602 for(idx=0; idx<num_files; idx++, counted++){
6603 sprintf(str, "%s.pof", pof_list[idx]);
6604 model_num = model_load(str, 0, NULL);
6606 pm = model_get(model_num);
6608 // if we have a real model
6613 // go through and print all raw submodels
6614 cfputs("RAW\n", out);
6617 for (i=0; i<pm->n_models; i++) {
6618 total = submodel_get_num_polys(model_num, i);
6620 model_total += total;
6621 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6624 sprintf(str, "Model total %d\n", model_total);
6627 // now go through and do it by LOD
6628 cfputs("BY LOD\n\n", out);
6629 for(i=0; i<pm->n_detail_levels; i++){
6630 sprintf(str, "LOD %d\n", i);
6634 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6636 destroyed_total = 0;
6637 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6638 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6641 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6644 sprintf(str, "TOTAL: %d\n", total + root_total);
6646 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6648 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6651 cfputs("------------------------------------------------------------------------\n\n", out);
6655 if(counted >= MAX_POLYGON_MODELS - 5){
6668 game_spew_pof_info();
6671 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6676 // Don't let more than one instance of Freespace run.
6677 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6679 SetForegroundWindow(hwnd);
6684 // Find out how much RAM is on this machine
6687 ms.dwLength = sizeof(MEMORYSTATUS);
6688 GlobalMemoryStatus(&ms);
6689 Freespace_total_ram = ms.dwTotalPhys;
6691 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6695 if ( ms.dwTotalVirtual < 1024 ) {
6696 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6700 if (!vm_init(24*1024*1024)) {
6701 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 );
6705 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6707 MessageBox(NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK);
6717 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6718 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6719 seem worth bothering with.
6723 lResult = RegOpenKeyEx(
6724 HKEY_LOCAL_MACHINE, // Where it is
6725 "Software\\Microsoft\\DirectX", // name of key
6726 NULL, // DWORD reserved
6727 KEY_QUERY_VALUE, // Allows all changes
6728 &hKey // Location to store key
6731 if (lResult == ERROR_SUCCESS) {
6733 DWORD dwType, dwLen;
6736 lResult = RegQueryValueEx(
6737 hKey, // Handle to key
6738 "Version", // The values name
6739 NULL, // DWORD reserved
6740 &dwType, // What kind it is
6741 (ubyte *) version, // value to set
6742 &dwLen // How many bytes to set
6745 if (lResult == ERROR_SUCCESS) {
6746 dx_version = atoi(strstr(version, ".") + 1);
6750 DWORD dwType, dwLen;
6753 lResult = RegQueryValueEx(
6754 hKey, // Handle to key
6755 "InstalledVersion", // The values name
6756 NULL, // DWORD reserved
6757 &dwType, // What kind it is
6758 (ubyte *) &val, // value to set
6759 &dwLen // How many bytes to set
6762 if (lResult == ERROR_SUCCESS) {
6770 if (dx_version < 3) {
6771 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6772 "latest version of DirectX at:\n\n"
6773 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6775 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6776 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6781 //=====================================================
6782 // Make sure we're running in the right directory.
6786 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6787 char *p = exe_dir + strlen(exe_dir);
6789 // chop off the filename
6790 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6796 if ( strlen(exe_dir) > 0 ) {
6797 SetCurrentDirectory(exe_dir);
6800 // check for updated freespace.exe
6801 game_maybe_update_launcher(exe_dir);
6809 extern void windebug_memwatch_init();
6810 windebug_memwatch_init();
6814 parse_cmdline(szCmdLine);
6816 #ifdef STANDALONE_ONLY_BUILD
6818 nprintf(("Network", "Standalone running"));
6821 nprintf(("Network", "Standalone running"));
6829 // maybe spew pof stuff
6830 if(Cmdline_spew_pof_info){
6831 game_spew_pof_info();
6836 // non-demo, non-standalone, play the intro movie
6841 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) ){
6843 #if defined(OEM_BUILD)
6844 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6846 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6847 #endif // defined(OEM_BUILD)
6852 if ( !Is_standalone ) {
6854 // release -- movies always play
6857 // 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
6859 // movie_play( NOX("intro.mve"), 0 );
6861 // debug version, movie will only play with -showmovies
6862 #elif !defined(NDEBUG)
6865 // movie_play( NOX("intro.mve"), 0);
6868 if ( Cmdline_show_movies )
6869 movie_play( NOX("intro.mve"), 0 );
6878 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6880 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6884 // only important for non THREADED mode
6887 state = gameseq_process_events();
6888 if ( state == GS_STATE_QUIT_GAME ){
6895 demo_upsell_show_screens();
6897 #elif defined(OEM_BUILD)
6898 // show upsell screens on exit
6899 oem_upsell_show_screens();
6906 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6912 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6914 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6916 // Do nothing here - RecordExceptionInfo() has already done
6917 // everything that is needed. Actually this code won't even
6918 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6919 // the __except clause.
6925 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6926 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6932 // launcher the fslauncher program on exit
6933 void game_launch_launcher_on_exit()
6937 PROCESS_INFORMATION pi;
6938 char cmd_line[2048];
6939 char original_path[1024] = "";
6941 memset( &si, 0, sizeof(STARTUPINFO) );
6945 _getcwd(original_path, 1023);
6947 // set up command line
6948 strcpy(cmd_line, original_path);
6949 strcat(cmd_line, "\\");
6950 strcat(cmd_line, LAUNCHER_FNAME);
6951 strcat(cmd_line, " -straight_to_update");
6953 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6954 cmd_line, // pointer to command line string
6955 NULL, // pointer to process security attributes
6956 NULL, // pointer to thread security attributes
6957 FALSE, // handle inheritance flag
6958 CREATE_DEFAULT_ERROR_MODE, // creation flags
6959 NULL, // pointer to new environment block
6960 NULL, // pointer to current directory name
6961 &si, // pointer to STARTUPINFO
6962 &pi // pointer to PROCESS_INFORMATION
6964 // to eliminate build warnings
6974 // This function is called when FreeSpace terminates normally.
6976 void game_shutdown(void)
6982 // don't ever flip a page on the standalone!
6983 if(!(Game_mode & GM_STANDALONE_SERVER)){
6989 // if the player has left the "player select" screen and quit the game without actually choosing
6990 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6991 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6995 // load up common multiplayer icons
6996 multi_unload_common_icons();
6998 shockwave_close(); // release any memory used by shockwave system
6999 fireball_close(); // free fireball system
7000 ship_close(); // free any memory that was allocated for the ships
7001 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7002 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7003 bm_unload_all(); // free bitmaps
7004 mission_campaign_close(); // close out the campaign stuff
7005 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7007 #ifdef MULTI_USE_LAG
7011 // the menu close functions will unload the bitmaps if they were displayed during the game
7012 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7015 training_menu_close();
7018 extern void joy_close();
7021 audiostream_close();
7023 event_music_close();
7027 // HACKITY HACK HACK
7028 // if this flag is set, we should be firing up the launcher when exiting freespace
7029 extern int Multi_update_fireup_launcher_on_exit;
7030 if(Multi_update_fireup_launcher_on_exit){
7031 game_launch_launcher_on_exit();
7035 // game_stop_looped_sounds()
7037 // This function will call the appropriate stop looped sound functions for those
7038 // modules which use looping sounds. It is not enough just to stop a looping sound
7039 // at the DirectSound level, the game is keeping track of looping sounds, and this
7040 // function is used to inform the game that looping sounds are being halted.
7042 void game_stop_looped_sounds()
7044 hud_stop_looped_locking_sounds();
7045 hud_stop_looped_engine_sounds();
7046 afterburner_stop_sounds();
7047 player_stop_looped_sounds();
7048 obj_snd_stop_all(); // stop all object-linked persistant sounds
7049 game_stop_subspace_ambient_sound();
7050 snd_stop(Radar_static_looping);
7051 Radar_static_looping = -1;
7052 snd_stop(Target_static_looping);
7053 shipfx_stop_engine_wash_sound();
7054 Target_static_looping = -1;
7057 //////////////////////////////////////////////////////////////////////////
7059 // Code for supporting an animating mouse pointer
7062 //////////////////////////////////////////////////////////////////////////
7064 typedef struct animating_obj
7073 static animating_obj Animating_mouse;
7075 // ----------------------------------------------------------------------------
7076 // init_animating_pointer()
7078 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7079 // gets properly initialized
7081 void init_animating_pointer()
7083 Animating_mouse.first_frame = -1;
7084 Animating_mouse.num_frames = 0;
7085 Animating_mouse.current_frame = -1;
7086 Animating_mouse.time = 0.0f;
7087 Animating_mouse.elapsed_time = 0.0f;
7090 // ----------------------------------------------------------------------------
7091 // load_animating_pointer()
7093 // Called at game init to load in the frames for the animating mouse pointer
7095 // input: filename => filename of animation file that holds the animation
7097 void load_animating_pointer(char *filename, int dx, int dy)
7102 init_animating_pointer();
7104 am = &Animating_mouse;
7105 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7106 if ( am->first_frame == -1 )
7107 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7108 am->current_frame = 0;
7109 am->time = am->num_frames / i2fl(fps);
7112 // ----------------------------------------------------------------------------
7113 // unload_animating_pointer()
7115 // Called at game shutdown to free the memory used to store the animation frames
7117 void unload_animating_pointer()
7122 am = &Animating_mouse;
7123 for ( i = 0; i < am->num_frames; i++ ) {
7124 Assert( (am->first_frame+i) >= 0 );
7125 bm_release(am->first_frame + i);
7128 am->first_frame = -1;
7130 am->current_frame = -1;
7133 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7134 void game_render_mouse(float frametime)
7139 // if animating cursor exists, play the next frame
7140 am = &Animating_mouse;
7141 if ( am->first_frame != -1 ) {
7142 mouse_get_pos(&mx, &my);
7143 am->elapsed_time += frametime;
7144 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7145 if ( am->current_frame >= am->num_frames ) {
7146 am->current_frame = 0;
7147 am->elapsed_time = 0.0f;
7149 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7153 // ----------------------------------------------------------------------------
7154 // game_maybe_draw_mouse()
7156 // determines whether to draw the mouse pointer at all, and what frame of
7157 // animation to use if the mouse is animating
7159 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7161 // input: frametime => elapsed frame time in seconds since last call
7163 void game_maybe_draw_mouse(float frametime)
7167 game_state = gameseq_get_state();
7169 switch ( game_state ) {
7170 case GS_STATE_GAME_PAUSED:
7171 // case GS_STATE_MULTI_PAUSED:
7172 case GS_STATE_GAME_PLAY:
7173 case GS_STATE_DEATH_DIED:
7174 case GS_STATE_DEATH_BLEW_UP:
7175 if ( popup_active() || popupdead_is_active() ) {
7187 if ( !Mouse_hidden )
7188 game_render_mouse(frametime);
7192 void game_do_training_checks()
7196 waypoint_list *wplp;
7198 if (Training_context & TRAINING_CONTEXT_SPEED) {
7199 s = (int) Player_obj->phys_info.fspeed;
7200 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7201 if (!Training_context_speed_set) {
7202 Training_context_speed_set = 1;
7203 Training_context_speed_timestamp = timestamp();
7207 Training_context_speed_set = 0;
7210 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7211 wplp = &Waypoint_lists[Training_context_path];
7212 if (wplp->count > Training_context_goal_waypoint) {
7213 i = Training_context_goal_waypoint;
7215 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7216 if (d <= Training_context_distance) {
7217 Training_context_at_waypoint = i;
7218 if (Training_context_goal_waypoint == i) {
7219 Training_context_goal_waypoint++;
7220 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7227 if (i == wplp->count)
7230 } while (i != Training_context_goal_waypoint);
7234 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7235 Players_target = Player_ai->target_objnum;
7236 Players_targeted_subsys = Player_ai->targeted_subsys;
7237 Players_target_timestamp = timestamp();
7241 /////////// Following is for event debug view screen
7245 #define EVENT_DEBUG_MAX 5000
7246 #define EVENT_DEBUG_EVENT 0x8000
7248 int Event_debug_index[EVENT_DEBUG_MAX];
7251 void game_add_event_debug_index(int n, int indent)
7253 if (ED_count < EVENT_DEBUG_MAX)
7254 Event_debug_index[ED_count++] = n | (indent << 16);
7257 void game_add_event_debug_sexp(int n, int indent)
7262 if (Sexp_nodes[n].first >= 0) {
7263 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7264 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7268 game_add_event_debug_index(n, indent);
7269 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7270 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7272 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7275 void game_event_debug_init()
7280 for (e=0; e<Num_mission_events; e++) {
7281 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7282 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7286 void game_show_event_debug(float frametime)
7290 int font_height, font_width;
7292 static int scroll_offset = 0;
7294 k = game_check_key();
7300 if (scroll_offset < 0)
7310 scroll_offset -= 20;
7311 if (scroll_offset < 0)
7316 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7320 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7326 gr_set_color_fast(&Color_bright);
7328 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7330 gr_set_color_fast(&Color_normal);
7332 gr_get_string_size(&font_width, &font_height, NOX("test"));
7333 y_max = gr_screen.max_h - font_height - 5;
7337 while (k < ED_count) {
7338 if (y_index > y_max)
7341 z = Event_debug_index[k];
7342 if (z & EVENT_DEBUG_EVENT) {
7344 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7345 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7346 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7347 Mission_events[z].repeat_count, Mission_events[z].interval);
7355 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7356 switch (Sexp_nodes[z & 0x7fff].value) {
7358 strcat(buf, NOX(" (True)"));
7362 strcat(buf, NOX(" (False)"));
7365 case SEXP_KNOWN_TRUE:
7366 strcat(buf, NOX(" (Always true)"));
7369 case SEXP_KNOWN_FALSE:
7370 strcat(buf, NOX(" (Always false)"));
7373 case SEXP_CANT_EVAL:
7374 strcat(buf, NOX(" (Can't eval)"));
7378 case SEXP_NAN_FOREVER:
7379 strcat(buf, NOX(" (Not a number)"));
7384 gr_printf(10, y_index, buf);
7385 y_index += font_height;
7398 extern int Tmap_npixels;
7400 int Tmap_num_too_big = 0;
7401 int Num_models_needing_splitting = 0;
7403 void Time_model( int modelnum )
7405 // mprintf(( "Timing ship '%s'\n", si->name ));
7407 vector eye_pos, model_pos;
7408 matrix eye_orient, model_orient;
7410 polymodel *pm = model_get( modelnum );
7412 int l = strlen(pm->filename);
7414 if ( (l == '/') || (l=='\\') || (l==':')) {
7420 char *pof_file = &pm->filename[l];
7422 int model_needs_splitting = 0;
7424 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7426 for (i=0; i<pm->n_textures; i++ ) {
7427 char filename[1024];
7430 int bmp_num = pm->original_textures[i];
7431 if ( bmp_num > -1 ) {
7432 bm_get_palette(pm->original_textures[i], pal, filename );
7434 bm_get_info( pm->original_textures[i],&w, &h );
7437 if ( (w > 512) || (h > 512) ) {
7438 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7440 model_needs_splitting++;
7443 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7447 if ( model_needs_splitting ) {
7448 Num_models_needing_splitting++;
7450 eye_orient = model_orient = vmd_identity_matrix;
7451 eye_pos = model_pos = vmd_zero_vector;
7453 eye_pos.z = -pm->rad*2.0f;
7455 vector eye_to_model;
7457 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7458 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7460 fix t1 = timer_get_fixed_seconds();
7463 ta.p = ta.b = ta.h = 0.0f;
7468 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7470 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7472 modelstats_num_polys = modelstats_num_verts = 0;
7474 while( ta.h < PI2 ) {
7477 vm_angles_2_matrix(&m1, &ta );
7478 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7485 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7487 model_clear_instance( modelnum );
7488 model_set_detail_level(0); // use highest detail level
7489 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7497 int k = key_inkey();
7498 if ( k == KEY_ESC ) {
7503 fix t2 = timer_get_fixed_seconds();
7505 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7506 //bitmaps_used_this_frame /= framecount;
7508 modelstats_num_polys /= framecount;
7509 modelstats_num_verts /= framecount;
7511 Tmap_npixels /=framecount;
7514 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7515 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 );
7516 // 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 );
7522 int Time_models = 0;
7523 DCF_BOOL( time_models, Time_models );
7525 void Do_model_timings_test()
7529 if ( !Time_models ) return;
7531 mprintf(( "Timing models!\n" ));
7535 ubyte model_used[MAX_POLYGON_MODELS];
7536 int model_id[MAX_POLYGON_MODELS];
7537 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7542 for (i=0; i<Num_ship_types; i++ ) {
7543 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7545 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7546 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7549 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7550 if ( !Texture_fp ) return;
7552 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7553 if ( !Time_fp ) return;
7555 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7556 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7558 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7559 if ( model_used[i] ) {
7560 Time_model( model_id[i] );
7564 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7565 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7574 // Call this function when you want to inform the player that a feature is not
7575 // enabled in the DEMO version of FreSpace
7576 void game_feature_not_in_demo_popup()
7578 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7581 // format the specified time (fixed point) into a nice string
7582 void game_format_time(fix m_time,char *time_str)
7585 int hours,minutes,seconds;
7588 mtime = f2fl(m_time);
7590 // get the hours, minutes and seconds
7591 hours = (int)(mtime / 3600.0f);
7593 mtime -= (3600.0f * (float)hours);
7595 seconds = (int)mtime%60;
7596 minutes = (int)mtime/60;
7598 // print the hour if necessary
7600 sprintf(time_str,XSTR( "%d:", 201),hours);
7601 // if there are less than 10 minutes, print a leading 0
7603 strcpy(tmp,NOX("0"));
7604 strcat(time_str,tmp);
7608 // print the minutes
7610 sprintf(tmp,XSTR( "%d:", 201),minutes);
7611 strcat(time_str,tmp);
7613 sprintf(time_str,XSTR( "%d:", 201),minutes);
7616 // print the seconds
7618 strcpy(tmp,NOX("0"));
7619 strcat(time_str,tmp);
7621 sprintf(tmp,"%d",seconds);
7622 strcat(time_str,tmp);
7625 // Stuff version string in *str.
7626 void get_version_string(char *str)
7629 if ( FS_VERSION_BUILD == 0 ) {
7630 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7632 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7635 #if defined (FS2_DEMO)
7637 #elif defined (OEM_BUILD)
7638 strcat(str, " (OEM)");
7644 char myname[_MAX_PATH];
7645 int namelen, major, minor, build, waste;
7646 unsigned int buf_size;
7652 // Find my EXE file name
7653 hMod = GetModuleHandle(NULL);
7654 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7656 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7657 infop = (char *)malloc(version_size);
7658 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7660 // get the product version
7661 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7662 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7664 sprintf(str,"Dv%d.%02d",major, minor);
7666 sprintf(str,"v%d.%02d",major, minor);
7671 void get_version_string_short(char *str)
7673 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7676 // ----------------------------------------------------------------
7678 // OEM UPSELL SCREENS BEGIN
7680 // ----------------------------------------------------------------
7681 #if defined(OEM_BUILD)
7683 #define NUM_OEM_UPSELL_SCREENS 3
7684 #define OEM_UPSELL_SCREEN_DELAY 10000
7686 static int Oem_upsell_bitmaps_loaded = 0;
7687 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7688 static int Oem_upsell_screen_number = 0;
7689 static int Oem_upsell_show_next_bitmap_time;
7692 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7705 static int Oem_normal_cursor = -1;
7706 static int Oem_web_cursor = -1;
7707 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7708 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7710 void oem_upsell_next_screen()
7712 Oem_upsell_screen_number++;
7713 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7714 // extra long delay, mouse shown on last upsell
7715 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7719 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7723 void oem_upsell_load_bitmaps()
7727 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7728 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7732 void oem_upsell_unload_bitmaps()
7736 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7737 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7738 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7743 Oem_upsell_bitmaps_loaded = 0;
7746 // clickable hotspot on 3rd OEM upsell screen
7747 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7749 28, 350, 287, 96 // x, y, w, h
7752 45, 561, 460, 152 // x, y, w, h
7756 void oem_upsell_show_screens()
7758 int current_time, k;
7761 if ( !Oem_upsell_bitmaps_loaded ) {
7762 oem_upsell_load_bitmaps();
7763 Oem_upsell_bitmaps_loaded = 1;
7766 // may use upsell screens more than once
7767 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7768 Oem_upsell_screen_number = 0;
7774 int nframes; // used to pass, not really needed (should be 1)
7775 Oem_normal_cursor = gr_get_cursor_bitmap();
7776 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7777 Assert(Oem_web_cursor >= 0);
7778 if (Oem_web_cursor < 0) {
7779 Oem_web_cursor = Oem_normal_cursor;
7784 //oem_reset_trailer_timer();
7786 current_time = timer_get_milliseconds();
7791 // advance screen on keypress or timeout
7792 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7793 oem_upsell_next_screen();
7796 // check if we are done
7797 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7798 Oem_upsell_screen_number--;
7801 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7806 // show me the upsell
7807 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7808 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7812 // if this is the 3rd upsell, make it clickable, d00d
7813 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7815 int button_state = mouse_get_pos(&mx, &my);
7816 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])
7817 && (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]) )
7820 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7823 if (button_state & MOUSE_LEFT_BUTTON) {
7825 multi_pxo_url(OEM_UPSELL_URL);
7829 // switch cursor back to normal one
7830 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7835 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7845 oem_upsell_unload_bitmaps();
7847 // switch cursor back to normal one
7848 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7852 #endif // defined(OEM_BUILD)
7853 // ----------------------------------------------------------------
7855 // OEM UPSELL SCREENS END
7857 // ----------------------------------------------------------------
7861 // ----------------------------------------------------------------
7863 // DEMO UPSELL SCREENS BEGIN
7865 // ----------------------------------------------------------------
7869 //#define NUM_DEMO_UPSELL_SCREENS 4
7871 #define NUM_DEMO_UPSELL_SCREENS 2
7872 #define DEMO_UPSELL_SCREEN_DELAY 3000
7874 static int Demo_upsell_bitmaps_loaded = 0;
7875 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7876 static int Demo_upsell_screen_number = 0;
7877 static int Demo_upsell_show_next_bitmap_time;
7880 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7893 void demo_upsell_next_screen()
7895 Demo_upsell_screen_number++;
7896 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7897 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7899 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7903 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7904 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7905 #ifndef HARDWARE_ONLY
7906 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7913 void demo_upsell_load_bitmaps()
7917 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7918 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7922 void demo_upsell_unload_bitmaps()
7926 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7927 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7928 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7933 Demo_upsell_bitmaps_loaded = 0;
7936 void demo_upsell_show_screens()
7938 int current_time, k;
7941 if ( !Demo_upsell_bitmaps_loaded ) {
7942 demo_upsell_load_bitmaps();
7943 Demo_upsell_bitmaps_loaded = 1;
7946 // may use upsell screens more than once
7947 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7948 Demo_upsell_screen_number = 0;
7955 demo_reset_trailer_timer();
7957 current_time = timer_get_milliseconds();
7964 // don't time out, wait for keypress
7966 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7967 demo_upsell_next_screen();
7972 demo_upsell_next_screen();
7975 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7976 Demo_upsell_screen_number--;
7979 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7984 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7985 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7990 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8000 demo_upsell_unload_bitmaps();
8005 // ----------------------------------------------------------------
8007 // DEMO UPSELL SCREENS END
8009 // ----------------------------------------------------------------
8012 // ----------------------------------------------------------------
8014 // Subspace Ambient Sound START
8016 // ----------------------------------------------------------------
8018 static int Subspace_ambient_left_channel = -1;
8019 static int Subspace_ambient_right_channel = -1;
8022 void game_start_subspace_ambient_sound()
8024 if ( Subspace_ambient_left_channel < 0 ) {
8025 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8028 if ( Subspace_ambient_right_channel < 0 ) {
8029 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8033 void game_stop_subspace_ambient_sound()
8035 if ( Subspace_ambient_left_channel >= 0 ) {
8036 snd_stop(Subspace_ambient_left_channel);
8037 Subspace_ambient_left_channel = -1;
8040 if ( Subspace_ambient_right_channel >= 0 ) {
8041 snd_stop(Subspace_ambient_right_channel);
8042 Subspace_ambient_right_channel = -1;
8046 // ----------------------------------------------------------------
8048 // Subspace Ambient Sound END
8050 // ----------------------------------------------------------------
8052 // ----------------------------------------------------------------
8054 // CDROM detection code START
8056 // ----------------------------------------------------------------
8058 #define CD_SIZE_72_MINUTE_MAX (697000000)
8060 uint game_get_cd_used_space(char *path)
8064 char use_path[512] = "";
8065 char sub_path[512] = "";
8066 WIN32_FIND_DATA find;
8069 // recurse through all files and directories
8070 strcpy(use_path, path);
8071 strcat(use_path, "*.*");
8072 find_handle = FindFirstFile(use_path, &find);
8075 if(find_handle == INVALID_HANDLE_VALUE){
8081 // subdirectory. make sure to ignore . and ..
8082 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8084 strcpy(sub_path, path);
8085 strcat(sub_path, find.cFileName);
8086 strcat(sub_path, "\\");
8087 total += game_get_cd_used_space(sub_path);
8089 total += (uint)find.nFileSizeLow;
8091 } while(FindNextFile(find_handle, &find));
8094 FindClose(find_handle);
8106 // if volume_name is non-null, the CD name must match that
8107 int find_freespace_cd(char *volume_name)
8110 char oldpath[MAX_PATH];
8114 int volume_match = 0;
8118 GetCurrentDirectory(MAX_PATH, oldpath);
8120 for (i = 0; i < 26; i++)
8126 path[0] = (char)('A'+i);
8127 if (GetDriveType(path) == DRIVE_CDROM) {
8129 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8130 nprintf(("CD", "CD volume: %s\n", volume));
8132 // check for any CD volume
8133 int volume1_present = 0;
8134 int volume2_present = 0;
8135 int volume3_present = 0;
8137 char full_check[512] = "";
8139 // look for setup.exe
8140 strcpy(full_check, path);
8141 strcat(full_check, "setup.exe");
8142 find_handle = _findfirst(full_check, &find);
8143 if(find_handle != -1){
8144 volume1_present = 1;
8145 _findclose(find_handle);
8148 // look for intro.mve
8149 strcpy(full_check, path);
8150 strcat(full_check, "intro.mve");
8151 find_handle = _findfirst(full_check, &find);
8152 if(find_handle != -1){
8153 volume2_present = 1;
8154 _findclose(find_handle);
8157 // look for endpart1.mve
8158 strcpy(full_check, path);
8159 strcat(full_check, "endpart1.mve");
8160 find_handle = _findfirst(full_check, &find);
8161 if(find_handle != -1){
8162 volume3_present = 1;
8163 _findclose(find_handle);
8166 // see if we have the specific CD we're looking for
8167 if ( volume_name ) {
8169 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8173 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8177 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8181 if ( volume1_present || volume2_present || volume3_present ) {
8186 // 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
8187 if ( volume_match ){
8189 // 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
8190 if(volume2_present || volume3_present) {
8191 // first step - check to make sure its a cdrom
8192 if(GetDriveType(path) != DRIVE_CDROM){
8196 #if !defined(OEM_BUILD)
8197 // oem not on 80 min cds, so dont check tha size
8199 uint used_space = game_get_cd_used_space(path);
8200 if(used_space < CD_SIZE_72_MINUTE_MAX){
8203 #endif // !defined(OEM_BUILD)
8211 #endif // RELEASE_REAL
8217 SetCurrentDirectory(oldpath);
8226 int set_cdrom_path(int drive_num)
8230 if (drive_num < 0) { //no CD
8232 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8235 strcpy(Game_CDROM_dir,""); //set directory
8239 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8255 i = find_freespace_cd();
8257 rval = set_cdrom_path(i);
8261 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8263 nprintf(("CD", "FreeSpace CD not found\n"));
8271 int Last_cd_label_found = 0;
8272 char Last_cd_label[256];
8274 int game_cd_changed()
8281 if ( strlen(Game_CDROM_dir) == 0 ) {
8285 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8287 if ( found != Last_cd_label_found ) {
8288 Last_cd_label_found = found;
8290 mprintf(( "CD '%s' was inserted\n", label ));
8293 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8297 if ( Last_cd_label_found ) {
8298 if ( !stricmp( Last_cd_label, label )) {
8299 //mprintf(( "CD didn't change\n" ));
8301 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8305 // none found before, none found now.
8306 //mprintf(( "still no CD...\n" ));
8310 Last_cd_label_found = found;
8312 strcpy( Last_cd_label, label );
8314 strcpy( Last_cd_label, "" );
8325 // check if _any_ FreeSpace2 CDs are in the drive
8326 // return: 1 => CD now in drive
8327 // 0 => Could not find CD, they refuse to put it in the drive
8328 int game_do_cd_check(char *volume_name)
8330 #if !defined(GAME_CD_CHECK)
8336 int num_attempts = 0;
8337 int refresh_files = 0;
8339 int path_set_ok, popup_rval;
8341 cd_drive_num = find_freespace_cd(volume_name);
8342 path_set_ok = set_cdrom_path(cd_drive_num);
8343 if ( path_set_ok ) {
8345 if ( refresh_files ) {
8357 // no CD found, so prompt user
8358 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8360 if ( popup_rval != 1 ) {
8365 if ( num_attempts++ > 5 ) {
8376 // check if _any_ FreeSpace2 CDs are in the drive
8377 // return: 1 => CD now in drive
8378 // 0 => Could not find CD, they refuse to put it in the drive
8379 int game_do_cd_check_specific(char *volume_name, int cdnum)
8384 int num_attempts = 0;
8385 int refresh_files = 0;
8387 int path_set_ok, popup_rval;
8389 cd_drive_num = find_freespace_cd(volume_name);
8390 path_set_ok = set_cdrom_path(cd_drive_num);
8391 if ( path_set_ok ) {
8393 if ( refresh_files ) {
8404 // no CD found, so prompt user
8405 #if defined(DVD_MESSAGE_HACK)
8406 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8408 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8411 if ( popup_rval != 1 ) {
8416 if ( num_attempts++ > 5 ) {
8426 // only need to do this in RELEASE_REAL
8427 int game_do_cd_mission_check(char *filename)
8433 fs_builtin_mission *m = game_find_builtin_mission(filename);
8435 // check for changed CD
8436 if(game_cd_changed()){
8441 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8445 // not builtin, so do a general check (any FS2 CD will do)
8447 return game_do_cd_check();
8450 // does not have any CD requirement, do a general check
8451 if(strlen(m->cd_volume) <= 0){
8452 return game_do_cd_check();
8456 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8458 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8460 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8463 return game_do_cd_check();
8466 // did we find the cd?
8467 if(find_freespace_cd(m->cd_volume) >= 0){
8471 // make sure the volume exists
8472 int num_attempts = 0;
8473 int refresh_files = 0;
8475 int path_set_ok, popup_rval;
8477 cd_drive_num = find_freespace_cd(m->cd_volume);
8478 path_set_ok = set_cdrom_path(cd_drive_num);
8479 if ( path_set_ok ) {
8481 if ( refresh_files ) {
8488 // no CD found, so prompt user
8489 #if defined(DVD_MESSAGE_HACK)
8490 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8492 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8496 if ( popup_rval != 1 ) {
8501 if ( num_attempts++ > 5 ) {
8513 // ----------------------------------------------------------------
8515 // CDROM detection code END
8517 // ----------------------------------------------------------------
8519 // ----------------------------------------------------------------
8520 // SHIPS TBL VERIFICATION STUFF
8523 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8524 #define NUM_SHIPS_TBL_CHECKSUMS 1
8526 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8527 -463907578, // US - beta 1
8528 1696074201, // FS2 demo
8531 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8532 // -1022810006, // 1.0 FULL
8533 -1254285366 // 1.2 FULL (German)
8536 void verify_ships_tbl()
8540 Game_ships_tbl_valid = 1;
8546 // detect if the packfile exists
8547 CFILE *detect = cfopen("ships.tbl", "rb");
8548 Game_ships_tbl_valid = 0;
8552 Game_ships_tbl_valid = 0;
8556 // get the long checksum of the file
8558 cfseek(detect, 0, SEEK_SET);
8559 cf_chksum_long(detect, &file_checksum);
8563 // now compare the checksum/filesize against known #'s
8564 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8565 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8566 Game_ships_tbl_valid = 1;
8573 DCF(shipspew, "display the checksum for the current ships.tbl")
8576 CFILE *detect = cfopen("ships.tbl", "rb");
8577 // get the long checksum of the file
8579 cfseek(detect, 0, SEEK_SET);
8580 cf_chksum_long(detect, &file_checksum);
8583 dc_printf("%d", file_checksum);
8586 // ----------------------------------------------------------------
8587 // WEAPONS TBL VERIFICATION STUFF
8590 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8591 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8593 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8594 141718090, // US - beta 1
8595 -266420030, // demo 1
8598 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8599 // 399297860, // 1.0 FULL
8600 -553984927 // 1.2 FULL (german)
8603 void verify_weapons_tbl()
8607 Game_weapons_tbl_valid = 1;
8613 // detect if the packfile exists
8614 CFILE *detect = cfopen("weapons.tbl", "rb");
8615 Game_weapons_tbl_valid = 0;
8619 Game_weapons_tbl_valid = 0;
8623 // get the long checksum of the file
8625 cfseek(detect, 0, SEEK_SET);
8626 cf_chksum_long(detect, &file_checksum);
8630 // now compare the checksum/filesize against known #'s
8631 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8632 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8633 Game_weapons_tbl_valid = 1;
8640 DCF(wepspew, "display the checksum for the current weapons.tbl")
8643 CFILE *detect = cfopen("weapons.tbl", "rb");
8644 // get the long checksum of the file
8646 cfseek(detect, 0, SEEK_SET);
8647 cf_chksum_long(detect, &file_checksum);
8650 dc_printf("%d", file_checksum);
8653 // if the game is running using hacked data
8654 int game_hacked_data()
8657 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8665 void display_title_screen()
8667 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8668 ///int title_bitmap;
8671 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8672 if (title_bitmap == -1) {
8677 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8678 extern void d3d_start_frame();
8683 gr_set_bitmap(title_bitmap);
8689 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8690 extern void d3d_stop_frame();
8697 bm_unload(title_bitmap);
8698 #endif // FS2_DEMO || OEM_BUILD
8701 // return true if the game is running with "low memory", which is less than 48MB
8702 bool game_using_low_mem()
8704 if (Use_low_mem == 0) {