2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
18 * Revision 1.29 2003/05/25 02:30:42 taylor
21 * Revision 1.28 2003/05/18 03:55:30 taylor
22 * automatic language selection support
24 * Revision 1.27 2003/03/03 04:54:44 theoddone33
25 * Commit Taylor's ShowFPS fix
27 * Revision 1.26 2003/02/20 17:41:07 theoddone33
28 * Userdir patch from Taylor Richards
30 * Revision 1.25 2003/01/30 19:54:10 relnev
31 * ini config option for the frames per second counter (Taylor Richards)
33 * Revision 1.24 2002/08/31 01:39:13 theoddone33
34 * Speed up the renderer a tad
36 * Revision 1.23 2002/08/04 02:31:00 relnev
37 * make numlock not overlap with pause
39 * Revision 1.22 2002/08/02 23:07:03 relnev
40 * don't access the mouse in standalone mode
42 * Revision 1.21 2002/07/28 05:05:08 relnev
43 * removed some old stuff
45 * Revision 1.20 2002/07/24 00:20:41 relnev
48 * Revision 1.19 2002/06/17 06:33:08 relnev
49 * ryan's struct patch for gcc 2.95
51 * Revision 1.18 2002/06/16 04:46:33 relnev
52 * set up correct checksums for demo
54 * Revision 1.17 2002/06/09 04:41:17 relnev
55 * added copyright header
57 * Revision 1.16 2002/06/09 03:16:04 relnev
60 * removed unneeded asm, old sdl 2d setup.
62 * fixed crash caused by opengl_get_region.
64 * Revision 1.15 2002/06/05 08:05:28 relnev
65 * stub/warning removal.
67 * reworked the sound code.
69 * Revision 1.14 2002/06/05 04:03:32 relnev
70 * finished cfilesystem.
72 * removed some old code.
74 * fixed mouse save off-by-one.
78 * Revision 1.13 2002/06/02 04:26:34 relnev
81 * Revision 1.12 2002/06/02 00:31:35 relnev
82 * implemented osregistry
84 * Revision 1.11 2002/06/01 09:00:34 relnev
85 * silly debug memmanager
87 * Revision 1.10 2002/06/01 07:12:32 relnev
88 * a few NDEBUG updates.
90 * removed a few warnings.
92 * Revision 1.9 2002/05/31 03:05:59 relnev
95 * Revision 1.8 2002/05/29 02:52:32 theoddone33
96 * Enable OpenGL renderer
98 * Revision 1.7 2002/05/28 08:52:03 relnev
99 * implemented two assembly stubs.
101 * cleaned up a few warnings.
103 * added a little demo hackery to make it progress a little farther.
105 * Revision 1.6 2002/05/28 06:28:20 theoddone33
106 * Filesystem mods, actually reads some data files now
108 * Revision 1.5 2002/05/28 04:07:28 theoddone33
109 * New graphics stubbing arrangement
111 * Revision 1.4 2002/05/27 22:46:52 theoddone33
112 * Remove more undefined symbols
114 * Revision 1.3 2002/05/26 23:31:18 relnev
115 * added a few files that needed to be compiled
117 * freespace.cpp: now compiles
119 * Revision 1.2 2002/05/07 03:16:44 theoddone33
120 * The Great Newline Fix
122 * Revision 1.1.1.1 2002/05/03 03:28:09 root
126 * 201 6/16/00 3:15p Jefff
127 * sim of the year dvd version changes, a few german soty localization
130 * 200 11/03/99 11:06a Jefff
133 * 199 10/26/99 5:07p Jamest
134 * fixed jeffs dumb debug code
136 * 198 10/25/99 5:53p Jefff
137 * call control_config_common_init() on startup
139 * 197 10/14/99 10:18a Daveb
140 * Fixed incorrect CD checking problem on standalone server.
142 * 196 10/13/99 9:22a Daveb
143 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
144 * related to movies. Fixed launcher spawning from PXO screen.
146 * 195 10/06/99 11:05a Jefff
147 * new oem upsell 3 hotspot coords
149 * 194 10/06/99 10:31a Jefff
152 * 193 10/01/99 9:10a Daveb
155 * 192 9/15/99 4:57a Dave
156 * Updated ships.tbl checksum
158 * 191 9/15/99 3:58a Dave
159 * Removed framerate warning at all times.
161 * 190 9/15/99 3:16a Dave
162 * Remove mt-011.fs2 from the builtin mission list.
164 * 189 9/15/99 1:45a Dave
165 * Don't init joystick on standalone. Fixed campaign mode on standalone.
166 * Fixed no-score-report problem in TvT
168 * 188 9/14/99 6:08a Dave
169 * Updated (final) single, multi, and campaign list.
171 * 187 9/14/99 3:26a Dave
172 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
173 * respawn-too-early problem. Made a few crash points safe.
175 * 186 9/13/99 4:52p Dave
178 * 185 9/12/99 8:09p Dave
179 * Fixed problem where skip-training button would cause mission messages
180 * not to get paged out for the current mission.
182 * 184 9/10/99 11:53a Dave
183 * Shutdown graphics before sound to eliminate apparent lockups when
184 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
186 * 183 9/09/99 11:40p Dave
187 * Handle an Assert() in beam code. Added supernova sounds. Play the right
188 * 2 end movies properly, based upon what the player did in the mission.
190 * 182 9/08/99 10:29p Dave
191 * Make beam sound pausing and unpausing much safer.
193 * 181 9/08/99 10:01p Dave
194 * Make sure game won't run in a drive's root directory. Make sure
195 * standalone routes suqad war messages properly to the host.
197 * 180 9/08/99 3:22p Dave
198 * Updated builtin mission list.
200 * 179 9/08/99 12:01p Jefff
201 * fixed Game_builtin_mission_list typo on Training-2.fs2
203 * 178 9/08/99 9:48a Andsager
204 * Add force feedback for engine wash.
206 * 177 9/07/99 4:01p Dave
207 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
208 * does everything properly (setting up address when binding). Remove
209 * black rectangle background from UI_INPUTBOX.
211 * 176 9/13/99 2:40a Dave
212 * Comment in full 80 minute CD check for RELEASE_REAL builds.
214 * 175 9/06/99 6:38p Dave
215 * Improved CD detection code.
217 * 174 9/06/99 1:30a Dave
218 * Intermediate checkin. Started on enforcing CD-in-drive to play the
221 * 173 9/06/99 1:16a Dave
222 * Make sure the user sees the intro movie.
224 * 172 9/04/99 8:00p Dave
225 * Fixed up 1024 and 32 bit movie support.
227 * 171 9/03/99 1:32a Dave
228 * CD checking by act. Added support to play 2 cutscenes in a row
229 * seamlessly. Fixed super low level cfile bug related to files in the
230 * root directory of a CD. Added cheat code to set campaign mission # in
233 * 170 9/01/99 10:49p Dave
234 * Added nice SquadWar checkbox to the client join wait screen.
236 * 169 9/01/99 10:14a Dave
239 * 168 8/29/99 4:51p Dave
240 * Fixed damaged checkin.
242 * 167 8/29/99 4:18p Andsager
243 * New "burst" limit for friendly damage. Also credit more damage done
244 * against large friendly ships.
246 * 166 8/27/99 6:38p Alanl
247 * crush the blasted repeating messages bug
249 * 164 8/26/99 9:09p Dave
250 * Force framerate check in everything but a RELEASE_REAL build.
252 * 163 8/26/99 9:45a Dave
253 * First pass at easter eggs and cheats.
255 * 162 8/24/99 8:55p Dave
256 * Make sure nondimming pixels work properly in tech menu.
258 * 161 8/24/99 1:49a Dave
259 * Fixed client-side afterburner stuttering. Added checkbox for no version
260 * checking on PXO join. Made button info passing more friendly between
263 * 160 8/22/99 5:53p Dave
264 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
265 * instead of ship designations for multiplayer players.
267 * 159 8/22/99 1:19p Dave
268 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
269 * which d3d cards are detected.
271 * 158 8/20/99 2:09p Dave
272 * PXO banner cycling.
274 * 157 8/19/99 10:59a Dave
275 * Packet loss detection.
277 * 156 8/19/99 10:12a Alanl
278 * preload mission-specific messages on machines greater than 48MB
280 * 155 8/16/99 4:04p Dave
281 * Big honking checkin.
283 * 154 8/11/99 5:54p Dave
284 * Fixed collision problem. Fixed standalone ghost problem.
286 * 153 8/10/99 7:59p Jefff
289 * 152 8/10/99 6:54p Dave
290 * Mad optimizations. Added paging to the nebula effect.
292 * 151 8/10/99 3:44p Jefff
293 * loads Intelligence information on startup
295 * 150 8/09/99 3:47p Dave
296 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
297 * non-nebula missions.
299 * 149 8/09/99 2:21p Andsager
300 * Fix patching from multiplayer direct to launcher update tab.
302 * 148 8/09/99 10:36a Dave
303 * Version info for game.
305 * 147 8/06/99 9:46p Dave
306 * Hopefully final changes for the demo.
308 * 146 8/06/99 3:34p Andsager
309 * Make title version info "(D)" -> "D" show up nicely
311 * 145 8/06/99 2:59p Adamp
312 * Fixed NT launcher/update problem.
314 * 144 8/06/99 1:52p Dave
315 * Bumped up MAX_BITMAPS for the demo.
317 * 143 8/06/99 12:17p Andsager
318 * Demo: down to just 1 demo dog
320 * 142 8/05/99 9:39p Dave
321 * Yet another new checksum.
323 * 141 8/05/99 6:19p Dave
324 * New demo checksums.
326 * 140 8/05/99 5:31p Andsager
327 * Up demo version 1.01
329 * 139 8/05/99 4:22p Andsager
330 * No time limit on upsell screens. Reverse order of display of upsell
333 * 138 8/05/99 4:17p Dave
334 * Tweaks to client interpolation.
336 * 137 8/05/99 3:52p Danw
338 * 136 8/05/99 3:01p Danw
340 * 135 8/05/99 2:43a Anoop
341 * removed duplicate definition.
343 * 134 8/05/99 2:13a Dave
346 * 133 8/05/99 2:05a Dave
349 * 132 8/05/99 1:22a Andsager
352 * 131 8/04/99 9:51p Andsager
353 * Add title screen to demo
355 * 130 8/04/99 6:47p Jefff
356 * fixed link error resulting from #ifdefs
358 * 129 8/04/99 6:26p Dave
359 * Updated ship tbl checksum.
361 * 128 8/04/99 5:40p Andsager
362 * Add multiple demo dogs
364 * 127 8/04/99 5:36p Andsager
365 * Show upsell screens at end of demo campaign before returning to main
368 * 126 8/04/99 11:42a Danw
369 * tone down EAX reverb
371 * 125 8/04/99 11:23a Dave
372 * Updated demo checksums.
374 * 124 8/03/99 11:02p Dave
375 * Maybe fixed sync problems in multiplayer.
377 * 123 8/03/99 6:21p Jefff
380 * 122 8/03/99 3:44p Andsager
381 * Launch laucher if trying to run FS without first having configured
384 * 121 8/03/99 12:45p Dave
387 * 120 8/02/99 9:13p Dave
390 * 119 7/30/99 10:31p Dave
391 * Added comm menu to the configurable hud files.
393 * 118 7/30/99 5:17p Andsager
394 * first fs2demo checksums
396 * 117 7/29/99 3:09p Anoop
398 * 116 7/29/99 12:05a Dave
399 * Nebula speed optimizations.
401 * 115 7/27/99 8:59a Andsager
402 * Make major, minor version consistent for all builds. Only show major
403 * and minor for launcher update window.
405 * 114 7/26/99 5:50p Dave
406 * Revised ingame join. Better? We'll see....
408 * 113 7/26/99 5:27p Andsager
409 * Add training mission as builtin to demo build
411 * 112 7/24/99 1:54p Dave
412 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
415 * 111 7/22/99 4:00p Dave
416 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
418 * 110 7/21/99 8:10p Dave
419 * First run of supernova effect.
421 * 109 7/20/99 1:49p Dave
422 * Peter Drake build. Fixed some release build warnings.
424 * 108 7/19/99 2:26p Andsager
425 * set demo multiplayer missions
427 * 107 7/18/99 5:19p Dave
428 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
430 * 106 7/16/99 1:50p Dave
431 * 8 bit aabitmaps. yay.
433 * 105 7/15/99 3:07p Dave
434 * 32 bit detection support. Mouse coord commandline.
436 * 104 7/15/99 2:13p Dave
437 * Added 32 bit detection.
439 * 103 7/15/99 9:20a Andsager
440 * FS2_DEMO initial checkin
442 * 102 7/14/99 11:02a Dave
443 * Skill level default back to easy. Blech.
445 * 101 7/09/99 5:54p Dave
446 * Seperated cruiser types into individual types. Added tons of new
447 * briefing icons. Campaign screen.
449 * 100 7/08/99 4:43p Andsager
450 * New check for sparky_hi and print if not found.
452 * 99 7/08/99 10:53a Dave
453 * New multiplayer interpolation scheme. Not 100% done yet, but still
454 * better than the old way.
456 * 98 7/06/99 4:24p Dave
457 * Mid-level checkin. Starting on some potentially cool multiplayer
460 * 97 7/06/99 3:35p Andsager
461 * Allow movie to play before red alert mission.
463 * 96 7/03/99 5:50p Dave
464 * Make rotated bitmaps draw properly in padlock views.
466 * 95 7/02/99 9:55p Dave
467 * Player engine wash sound.
469 * 94 7/02/99 4:30p Dave
470 * Much more sophisticated lightning support.
472 * 93 6/29/99 7:52p Dave
473 * Put in exception handling in FS2.
475 * 92 6/22/99 9:37p Dave
476 * Put in pof spewing.
478 * 91 6/16/99 4:06p Dave
479 * New pilot info popup. Added new draw-bitmap-as-poly function.
481 * 90 6/15/99 1:56p Andsager
482 * For release builds, allow start up in high res only with
485 * 89 6/15/99 9:34a Dave
486 * Fixed key checking in single threaded version of the stamp notification
489 * 88 6/09/99 2:55p Andsager
490 * Allow multiple asteroid subtypes (of large, medium, small) and follow
493 * 87 6/08/99 1:14a Dave
494 * Multi colored hud test.
496 * 86 6/04/99 9:52a Dave
497 * Fixed some rendering problems.
499 * 85 6/03/99 10:15p Dave
500 * Put in temporary main hall screen.
502 * 84 6/02/99 6:18p Dave
503 * Fixed TNT lockup problems! Wheeeee!
505 * 83 6/01/99 3:52p Dave
506 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
507 * dead popup, pxo find player popup, pxo private room popup.
509 * 82 5/26/99 1:28p Jasenw
510 * changed coords for loading ani
512 * 81 5/26/99 11:46a Dave
513 * Added ship-blasting lighting and made the randomization of lighting
514 * much more customizable.
516 * 80 5/24/99 5:45p Dave
517 * Added detail levels to the nebula, with a decent speedup. Split nebula
518 * lightning into its own section.
536 #include "systemvars.h"
541 #include "starfield.h"
542 #include "lighting.h"
547 #include "fireballs.h"
551 #include "floating.h"
552 #include "gamesequence.h"
554 #include "optionsmenu.h"
555 #include "playermenu.h"
556 #include "trainingmenu.h"
557 #include "techmenu.h"
560 #include "hudmessage.h"
562 #include "missiongoals.h"
563 #include "missionparse.h"
568 #include "multiutil.h"
569 #include "multimsgs.h"
573 #include "freespace.h"
574 #include "managepilot.h"
576 #include "contexthelp.h"
579 #include "missionbrief.h"
580 #include "missiondebrief.h"
582 #include "missionshipchoice.h"
584 #include "hudconfig.h"
585 #include "controlsconfig.h"
586 #include "missionmessage.h"
587 #include "missiontraining.h"
589 #include "hudtarget.h"
591 #include "eventmusic.h"
592 #include "animplay.h"
593 #include "missionweaponchoice.h"
594 #include "missionlog.h"
595 #include "audiostr.h"
597 #include "missioncampaign.h"
599 #include "missionhotkey.h"
600 #include "objectsnd.h"
601 #include "cmeasure.h"
603 #include "linklist.h"
604 #include "shockwave.h"
605 #include "afterburner.h"
610 #include "stand_gui.h"
611 #include "pcxutils.h"
612 #include "hudtargetbox.h"
613 #include "multi_xfer.h"
614 #include "hudescort.h"
615 #include "multiutil.h"
618 #include "multiteamselect.h"
621 #include "readyroom.h"
622 #include "mainhallmenu.h"
623 #include "multilag.h"
625 #include "particle.h"
627 #include "multi_ingame.h"
628 #include "snazzyui.h"
629 #include "asteroid.h"
630 #include "popupdead.h"
631 #include "multi_voice.h"
632 #include "missioncmdbrief.h"
633 #include "redalert.h"
634 #include "gameplayhelp.h"
635 #include "multilag.h"
636 #include "staticrand.h"
637 #include "multi_pmsg.h"
638 #include "levelpaging.h"
639 #include "observer.h"
640 #include "multi_pause.h"
641 #include "multi_endgame.h"
642 #include "cutscenes.h"
643 #include "multi_respawn.h"
645 #include "multi_obj.h"
646 #include "multi_log.h"
648 #include "localize.h"
649 #include "osregistry.h"
650 #include "barracks.h"
651 #include "missionpause.h"
653 #include "alphacolors.h"
654 #include "objcollide.h"
657 #include "neblightning.h"
658 #include "shipcontrails.h"
661 #include "multi_dogfight.h"
662 #include "multi_rate.h"
663 #include "muzzleflash.h"
667 #include "mainhalltemp.h"
668 #include "exceptionhandler.h"
672 #include "supernova.h"
673 #include "hudshield.h"
674 // #include "names.h"
676 #include "missionloopbrief.h"
680 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
686 // 1.00.04 5/26/98 MWA -- going final (12 pm)
687 // 1.00.03 5/26/98 MWA -- going final (3 am)
688 // 1.00.02 5/25/98 MWA -- going final
689 // 1.00.01 5/25/98 MWA -- going final
690 // 0.90 5/21/98 MWA -- getting ready for final.
691 // 0.10 4/9/98. Set by MK.
693 // Demo version: (obsolete since DEMO codebase split from tree)
694 // 0.03 4/10/98 AL. Interplay rev
695 // 0.02 4/8/98 MK. Increased when this system was modified.
696 // 0.01 4/7/98? AL. First release to Interplay QA.
699 // 1.00 5/28/98 AL. First release to Interplay QA.
701 void game_level_init(int seed = -1);
702 void game_post_level_init();
703 void game_do_frame();
704 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
705 void game_reset_time();
706 void game_show_framerate(); // draws framerate in lower right corner
708 int Game_no_clear = 0;
710 int Pofview_running = 0;
711 int Nebedit_running = 0;
713 typedef struct big_expl_flash {
714 float max_flash_intensity; // max intensity
715 float cur_flash_intensity; // cur intensity
716 int flash_start; // start time
719 #define FRAME_FILTER 16
721 #define DEFAULT_SKILL_LEVEL 1
722 int Game_skill_level = DEFAULT_SKILL_LEVEL;
724 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
725 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
727 #define EXE_FNAME ("fs2.exe")
728 #define LAUNCHER_FNAME ("freespace2.exe")
730 // JAS: Code for warphole camera.
731 // Needs to be cleaned up.
732 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
733 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
734 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
735 matrix Camera_orient = IDENTITY_MATRIX;
736 float Camera_damping = 1.0f;
737 float Camera_time = 0.0f;
738 float Warpout_time = 0.0f;
739 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
740 int Warpout_sound = -1;
742 int Use_joy_mouse = 0;
743 int Use_palette_flash = 1;
745 int Use_fullscreen_at_startup = 0;
747 int Show_area_effect = 0;
748 object *Last_view_target = NULL;
750 int dogfight_blown = 0;
753 float frametimes[FRAME_FILTER];
754 float frametotal = 0.0f;
758 int Show_framerate = 0;
760 int Show_framerate = 1;
763 int Framerate_cap = 120;
766 int Show_target_debug_info = 0;
767 int Show_target_weapons = 0;
771 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
774 int Debug_octant = -1;
776 fix Game_time_compression = F1_0;
778 // if the ships.tbl the player has is valid
779 int Game_ships_tbl_valid = 0;
781 // if the weapons.tbl the player has is valid
782 int Game_weapons_tbl_valid = 0;
786 extern int Player_attacking_enabled;
790 int Pre_player_entry;
792 int Fred_running = 0;
793 char Game_current_mission_filename[MAX_FILENAME_LEN];
794 int game_single_step = 0;
795 int last_single_step=0;
797 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
798 extern int MSG_WINDOW_Y_START;
799 extern int MSG_WINDOW_HEIGHT;
801 int game_zbuffer = 1;
802 //static int Game_music_paused;
803 static int Game_paused;
807 #define EXPIRE_BAD_CHECKSUM 1
808 #define EXPIRE_BAD_TIME 2
810 extern void ssm_init();
811 extern void ssm_level_init();
812 extern void ssm_process();
814 // static variable to contain the time this version was built
815 // commented out for now until
816 // I figure out how to get the username into the file
817 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
819 // defines and variables used for dumping frame for making trailers.
821 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
822 int Debug_dump_trigger = 0;
823 int Debug_dump_frame_count;
824 int Debug_dump_frame_num = 0;
825 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
828 // amount of time to wait after the player has died before we display the death died popup
829 #define PLAYER_DIED_POPUP_WAIT 2500
830 int Player_died_popup_wait = -1;
831 int Player_multi_died_check = -1;
833 // builtin mission list stuff
835 int Game_builtin_mission_count = 6;
836 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
837 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
838 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
839 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
840 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
841 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 #elif defined(FS1_DEMO)
845 int Game_builtin_mission_count = 5;
846 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
847 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
848 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
849 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
850 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
851 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
853 #elif defined(PD_BUILD)
854 int Game_builtin_mission_count = 4;
855 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
856 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
857 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
858 { "sm1-01", (FSB_FROM_VOLITION), "" },
859 { "sm1-05", (FSB_FROM_VOLITION), "" },
861 #elif defined(MULTIPLAYER_BETA)
862 int Game_builtin_mission_count = 17;
863 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
865 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
878 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
879 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
880 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
881 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
883 #elif defined(OEM_BUILD)
884 int Game_builtin_mission_count = 17;
885 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
886 // oem version - act 1 only
887 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
890 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
891 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
892 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
893 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
894 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
895 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
896 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
897 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
898 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
899 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
900 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
901 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
902 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
903 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
904 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
905 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
907 #elif defined(MAKE_FS1)
908 int Game_builtin_mission_count = 125;
909 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
910 // single player campaign
911 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
914 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
915 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
916 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
917 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
918 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
919 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
920 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
921 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
922 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
923 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
926 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
927 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
928 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
929 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
930 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
931 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
932 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
933 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
934 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
935 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
938 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
939 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
940 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
941 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
942 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
943 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
944 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
945 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
946 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
949 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
955 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
956 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
957 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
958 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
961 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
962 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
964 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
984 // SilentThreat missions
985 // Main SilentThreat campaign
986 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE), "" },
988 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
989 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
990 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
991 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
992 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
993 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
994 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
995 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
996 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
997 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
998 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
999 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1001 // SilentThreat Part 1 - multi-coop
1002 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1004 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1005 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1006 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1008 // SilentThreat Part 2 - multi-coop
1009 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1011 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1012 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1013 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1015 // SilentThreat Part 3 - multi-coop
1016 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1018 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1019 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1020 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1022 // SilentThreat Part 4 - multi-coop
1023 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1025 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1026 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1027 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1029 // multiplayer missions
1030 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1031 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1032 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1033 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1034 // user supplied missions
1035 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1036 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1037 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1038 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1039 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1040 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1041 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1042 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1043 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1044 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1045 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1046 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1047 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1048 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1049 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1050 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1051 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1052 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1053 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1054 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1055 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1056 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1057 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1058 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1059 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1060 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1061 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1062 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1063 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1064 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1065 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1066 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1069 int Game_builtin_mission_count = 92;
1070 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1071 // single player campaign
1072 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
1075 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1076 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1077 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1078 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1079 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1080 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1081 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1082 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1083 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1084 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1085 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1086 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1087 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1088 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1089 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1090 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1091 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1092 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1093 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1096 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1097 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1098 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1099 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1100 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1101 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1102 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1103 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1104 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1105 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1108 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1109 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1110 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1111 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1112 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1113 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1114 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1115 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1116 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1117 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1118 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1119 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1121 // multiplayer missions
1124 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1125 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1126 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1129 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1130 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1131 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1132 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1135 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1136 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1137 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1138 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1139 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1140 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1141 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1142 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1143 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1144 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1145 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1146 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1147 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1148 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1149 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1150 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1151 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1152 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1153 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1154 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1155 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1156 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1157 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1158 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1159 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1160 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1161 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1162 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1165 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1166 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1167 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1168 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1169 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1170 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1171 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1172 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1173 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1174 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1177 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1178 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1179 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1180 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1181 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1186 // Internal function prototypes
1187 void game_maybe_draw_mouse(float frametime);
1188 void init_animating_pointer();
1189 void load_animating_pointer(char *filename, int dx, int dy);
1190 void unload_animating_pointer();
1191 void game_do_training_checks();
1192 void game_shutdown(void);
1193 void game_show_event_debug(float frametime);
1194 void game_event_debug_init();
1196 void demo_upsell_show_screens();
1197 void game_start_subspace_ambient_sound();
1198 void game_stop_subspace_ambient_sound();
1199 void verify_ships_tbl();
1200 void verify_weapons_tbl();
1201 void display_title_screen();
1203 // loading background filenames
1204 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1205 "LoadingBG", // GR_640
1206 "2_LoadingBG" // GR_1024
1210 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1211 "Loading.ani", // GR_640
1212 "2_Loading.ani" // GR_1024
1215 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1216 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1224 #elif defined(OEM_BUILD)
1225 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1235 char Game_CDROM_dir[MAX_PATH_LEN];
1238 // How much RAM is on this machine. Set in WinMain
1239 uint Freespace_total_ram = 0;
1242 float Game_flash_red = 0.0f;
1243 float Game_flash_green = 0.0f;
1244 float Game_flash_blue = 0.0f;
1245 float Sun_spot = 0.0f;
1246 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1248 // game shudder stuff (in ms)
1249 int Game_shudder_time = -1;
1250 int Game_shudder_total = 0;
1251 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1254 sound_env Game_sound_env;
1255 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1256 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1258 int Game_sound_env_update_timestamp;
1260 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1263 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1265 fs_builtin_mission *game_find_builtin_mission(char *filename)
1269 // look through all existing builtin missions
1270 for(idx=0; idx<Game_builtin_mission_count; idx++){
1271 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1272 return &Game_builtin_mission_list[idx];
1280 int game_get_default_skill_level()
1282 return DEFAULT_SKILL_LEVEL;
1286 void game_flash_reset()
1288 Game_flash_red = 0.0f;
1289 Game_flash_green = 0.0f;
1290 Game_flash_blue = 0.0f;
1292 Big_expl_flash.max_flash_intensity = 0.0f;
1293 Big_expl_flash.cur_flash_intensity = 0.0f;
1294 Big_expl_flash.flash_start = 0;
1297 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1298 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1300 void game_framerate_check_init()
1302 // zero critical time
1303 Gf_critical_time = 0.0f;
1306 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1307 // if this is a glide card
1308 if(gr_screen.mode == GR_GLIDE){
1310 extern GrHwConfiguration hwconfig;
1313 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1314 Gf_critical = 15.0f;
1318 Gf_critical = 10.0f;
1323 Gf_critical = 15.0f;
1326 // d3d. only care about good cards here I guess (TNT)
1328 Gf_critical = 15.0f;
1331 // if this is a glide card
1332 if(gr_screen.mode == GR_GLIDE){
1334 extern GrHwConfiguration hwconfig;
1337 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1338 Gf_critical = 25.0f;
1342 Gf_critical = 20.0f;
1347 Gf_critical = 25.0f;
1350 // d3d. only care about good cards here I guess (TNT)
1352 Gf_critical = 25.0f;
1357 extern float Framerate;
1358 void game_framerate_check()
1362 // if the current framerate is above the critical level, add frametime
1363 if(Framerate >= Gf_critical){
1364 Gf_critical_time += flFrametime;
1367 if(!Show_framerate){
1371 // display if we're above the critical framerate
1372 if(Framerate < Gf_critical){
1373 gr_set_color_fast(&Color_bright_red);
1374 gr_string(200, y_start, "Framerate warning");
1379 // display our current pct of good frametime
1380 if(f2fl(Missiontime) >= 0.0f){
1381 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1384 gr_set_color_fast(&Color_bright_green);
1386 gr_set_color_fast(&Color_bright_red);
1389 gr_printf(200, y_start, "%d%%", (int)pct);
1396 // Adds a flash effect. These can be positive or negative.
1397 // The range will get capped at around -1 to 1, so stick
1398 // with a range like that.
1399 void game_flash( float r, float g, float b )
1401 Game_flash_red += r;
1402 Game_flash_green += g;
1403 Game_flash_blue += b;
1405 if ( Game_flash_red < -1.0f ) {
1406 Game_flash_red = -1.0f;
1407 } else if ( Game_flash_red > 1.0f ) {
1408 Game_flash_red = 1.0f;
1411 if ( Game_flash_green < -1.0f ) {
1412 Game_flash_green = -1.0f;
1413 } else if ( Game_flash_green > 1.0f ) {
1414 Game_flash_green = 1.0f;
1417 if ( Game_flash_blue < -1.0f ) {
1418 Game_flash_blue = -1.0f;
1419 } else if ( Game_flash_blue > 1.0f ) {
1420 Game_flash_blue = 1.0f;
1425 // Adds a flash for Big Ship explosions
1426 // cap range from 0 to 1
1427 void big_explosion_flash(float flash)
1429 Big_expl_flash.flash_start = timestamp(1);
1433 } else if (flash < 0.0f) {
1437 Big_expl_flash.max_flash_intensity = flash;
1438 Big_expl_flash.cur_flash_intensity = 0.0f;
1441 // Amount to diminish palette towards normal, per second.
1442 #define DIMINISH_RATE 0.75f
1443 #define SUN_DIMINISH_RATE 6.00f
1447 float sn_glare_scale = 1.7f;
1450 dc_get_arg(ARG_FLOAT);
1451 sn_glare_scale = Dc_arg_float;
1454 float Supernova_last_glare = 0.0f;
1455 void game_sunspot_process(float frametime)
1459 float Sun_spot_goal = 0.0f;
1462 sn_stage = supernova_active();
1464 // sunspot differently based on supernova stage
1466 // approaching. player still in control
1469 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1472 light_get_global_dir(&light_dir, 0);
1474 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1477 // scale it some more
1478 dot = dot * (0.5f + (pct * 0.5f));
1481 Sun_spot_goal += (dot * sn_glare_scale);
1484 // draw the sun glow
1485 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1486 // draw the glow for this sun
1487 stars_draw_sun_glow(0);
1490 Supernova_last_glare = Sun_spot_goal;
1493 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1496 Sun_spot_goal = 0.9f;
1497 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1499 if(Sun_spot_goal > 1.0f){
1500 Sun_spot_goal = 1.0f;
1503 Sun_spot_goal *= sn_glare_scale;
1504 Supernova_last_glare = Sun_spot_goal;
1507 // fade to white. display dead popup
1510 Supernova_last_glare += (2.0f * flFrametime);
1511 if(Supernova_last_glare > 2.0f){
1512 Supernova_last_glare = 2.0f;
1515 Sun_spot_goal = Supernova_last_glare;
1522 // check sunspots for all suns
1523 n_lights = light_get_global_count();
1526 for(idx=0; idx<n_lights; idx++){
1527 //(vector *eye_pos, matrix *eye_orient)
1528 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1531 light_get_global_dir(&light_dir, idx);
1533 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1535 Sun_spot_goal += (float)pow(dot,85.0f);
1537 // draw the glow for this sun
1538 stars_draw_sun_glow(idx);
1540 Sun_spot_goal = 0.0f;
1546 Sun_spot_goal = 0.0f;
1550 float dec_amount = frametime*SUN_DIMINISH_RATE;
1552 if ( Sun_spot < Sun_spot_goal ) {
1553 Sun_spot += dec_amount;
1554 if ( Sun_spot > Sun_spot_goal ) {
1555 Sun_spot = Sun_spot_goal;
1557 } else if ( Sun_spot > Sun_spot_goal ) {
1558 Sun_spot -= dec_amount;
1559 if ( Sun_spot < Sun_spot_goal ) {
1560 Sun_spot = Sun_spot_goal;
1566 // Call once a frame to diminish the
1567 // flash effect to 0.
1568 void game_flash_diminish(float frametime)
1570 float dec_amount = frametime*DIMINISH_RATE;
1572 if ( Game_flash_red > 0.0f ) {
1573 Game_flash_red -= dec_amount;
1574 if ( Game_flash_red < 0.0f )
1575 Game_flash_red = 0.0f;
1577 Game_flash_red += dec_amount;
1578 if ( Game_flash_red > 0.0f )
1579 Game_flash_red = 0.0f;
1582 if ( Game_flash_green > 0.0f ) {
1583 Game_flash_green -= dec_amount;
1584 if ( Game_flash_green < 0.0f )
1585 Game_flash_green = 0.0f;
1587 Game_flash_green += dec_amount;
1588 if ( Game_flash_green > 0.0f )
1589 Game_flash_green = 0.0f;
1592 if ( Game_flash_blue > 0.0f ) {
1593 Game_flash_blue -= dec_amount;
1594 if ( Game_flash_blue < 0.0f )
1595 Game_flash_blue = 0.0f;
1597 Game_flash_blue += dec_amount;
1598 if ( Game_flash_blue > 0.0f )
1599 Game_flash_blue = 0.0f;
1602 // update big_explosion_cur_flash
1603 #define TIME_UP 1500
1604 #define TIME_DOWN 2500
1605 int duration = TIME_UP + TIME_DOWN;
1606 int time = timestamp_until(Big_expl_flash.flash_start);
1607 if (time > -duration) {
1609 if (time < TIME_UP) {
1610 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1613 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1617 if ( Use_palette_flash ) {
1619 // static int or=0, og=0, ob=0;
1621 // Change the 200 to change the color range of colors.
1622 r = fl2i( Game_flash_red*128.0f );
1623 g = fl2i( Game_flash_green*128.0f );
1624 b = fl2i( Game_flash_blue*128.0f );
1626 if ( Sun_spot > 0.0f ) {
1627 r += fl2i(Sun_spot*128.0f);
1628 g += fl2i(Sun_spot*128.0f);
1629 b += fl2i(Sun_spot*128.0f);
1632 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1633 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1634 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1635 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1638 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1639 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1640 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1642 if ( (r!=0) || (g!=0) || (b!=0) ) {
1643 gr_flash( r, g, b );
1645 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1656 void game_level_close()
1658 // De-Initialize the game subsystems
1659 message_mission_shutdown();
1660 event_music_level_close();
1661 game_stop_looped_sounds();
1663 obj_snd_level_close(); // uninit object-linked persistant sounds
1664 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1665 anim_level_close(); // stop and clean up any anim instances
1666 shockwave_level_close();
1667 fireball_level_close();
1669 mission_event_shutdown();
1670 asteroid_level_close();
1671 model_cache_reset(); // Reset/free all the model caching stuff
1672 flak_level_close(); // unload flak stuff
1673 neb2_level_close(); // shutdown gaseous nebula stuff
1676 mflash_level_close();
1678 audiostream_unpause_all();
1683 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1684 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1685 void game_level_init(int seed)
1687 // seed the random number generator
1689 // if no seed was passed, seed the generator either from the time value, or from the
1690 // netgame security flags -- ensures that all players in multiplayer game will have the
1691 // same randon number sequence (with static rand functions)
1692 if ( Game_mode & GM_NORMAL ) {
1693 Game_level_seed = time(NULL);
1695 Game_level_seed = Netgame.security;
1698 // mwa 9/17/98 -- maybe this assert isn't needed????
1699 Assert( !(Game_mode & GM_MULTIPLAYER) );
1700 Game_level_seed = seed;
1702 srand( Game_level_seed );
1704 // semirand function needs to get re-initted every time in multiplayer
1705 if ( Game_mode & GM_MULTIPLAYER ){
1711 Key_normal_game = (Game_mode & GM_NORMAL);
1714 Game_shudder_time = -1;
1716 // Initialize the game subsystems
1717 // timestamp_reset(); // Must be inited before everything else
1719 game_reset_time(); // resets time, and resets saved time too
1721 obj_init(); // Must be inited before the other systems
1722 model_free_all(); // Free all existing models
1723 mission_brief_common_init(); // Free all existing briefing/debriefing text
1724 weapon_level_init();
1725 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1727 player_level_init();
1728 shipfx_flash_init(); // Init the ship gun flash system.
1729 game_flash_reset(); // Reset the flash effect
1730 particle_init(); // Reset the particle system
1734 shield_hit_init(); // Initialize system for showing shield hits
1735 radar_mission_init();
1736 mission_init_goals();
1739 obj_snd_level_init(); // init object-linked persistant sounds
1741 shockwave_level_init();
1742 afterburner_level_init();
1743 scoring_level_init( &Player->stats );
1745 asteroid_level_init();
1746 control_config_clear_used_status();
1747 collide_ship_ship_sounds_init();
1749 Pre_player_entry = 1; // Means the player has not yet entered.
1750 Entry_delay_time = 0; // Could get overwritten in mission read.
1751 fireball_preload(); // page in warphole bitmaps
1753 flak_level_init(); // initialize flak - bitmaps, etc
1754 ct_level_init(); // initialize ships contrails, etc
1755 awacs_level_init(); // initialize AWACS
1756 beam_level_init(); // initialize beam weapons
1757 mflash_level_init();
1759 supernova_level_init();
1761 // multiplayer dogfight hack
1764 shipfx_engine_wash_level_init();
1768 Last_view_target = NULL;
1773 // campaign wasn't ended
1774 Campaign_ended_in_mission = 0;
1777 // called when a mission is over -- does server specific stuff.
1778 void freespace_stop_mission()
1781 Game_mode &= ~GM_IN_MISSION;
1784 // called at frame interval to process networking stuff
1785 void game_do_networking()
1787 Assert( Net_player != NULL );
1788 if (!(Game_mode & GM_MULTIPLAYER)){
1792 // see if this player should be reading/writing data. Bit is set when at join
1793 // screen onward until quits back to main menu.
1794 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1798 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1801 multi_pause_do_frame();
1806 // Loads the best palette for this level, based
1807 // on nebula color and hud color. You could just call palette_load_table with
1808 // the appropriate filename, but who wants to do that.
1809 void game_load_palette()
1811 char palette_filename[1024];
1813 // We only use 3 hud colors right now
1815 Assert( HUD_config.main_color >= 0 );
1816 Assert( HUD_config.main_color <= 2 );
1819 Assert( Mission_palette >= 0 );
1820 Assert( Mission_palette <= 98 );
1823 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1824 strcpy( palette_filename, NOX("gamepalette-subspace") );
1826 sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1829 mprintf(( "Loading palette %s\n", palette_filename ));
1831 palette_load_table(palette_filename);
1833 strcpy( palette_filename, NOX("gamepalette-subspace") );
1835 mprintf(( "Loading palette %s\n", palette_filename ));
1839 void game_post_level_init()
1841 // Stuff which gets called after mission is loaded. Because player isn't created until
1842 // after mission loads, some things must get initted after the level loads
1844 model_level_post_init();
1847 hud_setup_escort_list();
1848 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1854 game_event_debug_init();
1857 training_mission_init();
1858 asteroid_create_all();
1860 game_framerate_check_init();
1864 // An estimate as to how high the count passed to game_loading_callback will go.
1865 // This is just a guess, it seems to always be about the same. The count is
1866 // proportional to the code being executed, not the time, so this works good
1867 // for a bar, assuming the code does about the same thing each time you
1868 // load a level. You can find this value by looking at the return value
1869 // of game_busy_callback(NULL), which I conveniently print out to the
1870 // debug output window with the '=== ENDING LOAD ==' stuff.
1871 //#define COUNT_ESTIMATE 3706
1872 #define COUNT_ESTIMATE 1111
1874 int Game_loading_callback_inited = 0;
1876 int Game_loading_background = -1;
1877 anim * Game_loading_ani = NULL;
1878 anim_instance *Game_loading_ani_instance;
1879 int Game_loading_frame=-1;
1881 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1883 #if defined(FS1_DEMO)
1885 #elif defined(MAKE_FS1)
1896 // This gets called 10x per second and count is the number of times
1897 // game_busy() has been called since the current callback function
1899 void game_loading_callback(int count)
1901 game_do_networking();
1903 Assert( Game_loading_callback_inited==1 );
1904 Assert( Game_loading_ani != NULL );
1906 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1907 if ( framenum > Game_loading_ani->total_frames-1 ) {
1908 framenum = Game_loading_ani->total_frames-1;
1909 } else if ( framenum < 0 ) {
1914 while ( Game_loading_frame < framenum ) {
1915 Game_loading_frame++;
1916 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1920 if ( cbitmap > -1 ) {
1921 if ( Game_loading_background > -1 ) {
1922 gr_set_bitmap( Game_loading_background );
1926 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1927 gr_set_bitmap( cbitmap );
1928 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1930 bm_release(cbitmap);
1936 void game_loading_callback_init()
1938 Assert( Game_loading_callback_inited==0 );
1940 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1942 common_set_interface_palette("InterfacePalette"); // set the interface palette
1946 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1947 Assert( Game_loading_ani != NULL );
1948 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1949 Assert( Game_loading_ani_instance != NULL );
1950 Game_loading_frame = -1;
1952 Game_loading_callback_inited = 1;
1954 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1959 void game_loading_callback_close()
1961 Assert( Game_loading_callback_inited==1 );
1963 // Make sure bar shows all the way over.
1964 game_loading_callback(COUNT_ESTIMATE);
1966 int real_count = game_busy_callback( NULL );
1969 Game_loading_callback_inited = 0;
1972 mprintf(( "=================== ENDING LOAD ================\n" ));
1973 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1974 mprintf(( "================================================\n" ));
1976 // to remove warnings in release build
1980 free_anim_instance(Game_loading_ani_instance);
1981 Game_loading_ani_instance = NULL;
1982 anim_free(Game_loading_ani);
1983 Game_loading_ani = NULL;
1985 bm_release( Game_loading_background );
1986 common_free_interface_palette(); // restore game palette
1987 Game_loading_background = -1;
1989 gr_set_font( FONT1 );
1992 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1994 void game_maybe_update_sound_environment()
1996 // do nothing for now
1999 // Assign the sound environment for the game, based on the current mission
2001 void game_assign_sound_environment()
2004 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
2005 Game_sound_env.id = SND_ENV_DRUGGED;
2006 Game_sound_env.volume = 0.800f;
2007 Game_sound_env.damping = 1.188f;
2008 Game_sound_env.decay = 6.392f;
2010 } else if (Num_asteroids > 30) {
2011 Game_sound_env.id = SND_ENV_AUDITORIUM;
2012 Game_sound_env.volume = 0.603f;
2013 Game_sound_env.damping = 0.5f;
2014 Game_sound_env.decay = 4.279f;
2017 Game_sound_env = Game_default_sound_env;
2021 Game_sound_env = Game_default_sound_env;
2022 Game_sound_env_update_timestamp = timestamp(1);
2025 // function which gets called before actually entering the mission. It is broken down into a funciton
2026 // since it will get called in one place from a single player game and from another place for
2027 // a multiplayer game
2028 void freespace_mission_load_stuff()
2030 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2031 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2032 if(!(Game_mode & GM_STANDALONE_SERVER)){
2034 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2036 game_loading_callback_init();
2038 event_music_level_init(); // preloads the first 2 seconds for each event music track
2041 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2044 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2047 ship_assign_sound_all(); // assign engine sounds to ships
2048 game_assign_sound_environment(); // assign the sound environment for this mission
2051 // call function in missionparse.cpp to fixup player/ai stuff.
2052 mission_parse_fixup_players();
2055 // Load in all the bitmaps for this level
2060 game_loading_callback_close();
2062 // the only thing we need to call on the standalone for now.
2064 // call function in missionparse.cpp to fixup player/ai stuff.
2065 mission_parse_fixup_players();
2067 // Load in all the bitmaps for this level
2073 uint load_mission_load;
2074 uint load_post_level_init;
2075 uint load_mission_stuff;
2077 // tells the server to load the mission and initialize structures
2078 int game_start_mission()
2080 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2082 load_gl_init = time(NULL);
2084 load_gl_init = time(NULL) - load_gl_init;
2086 if (Game_mode & GM_MULTIPLAYER) {
2087 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2089 // clear multiplayer stats
2090 init_multiplayer_stats();
2093 load_mission_load = time(NULL);
2094 if (mission_load()) {
2095 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2096 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2097 gameseq_post_event(GS_EVENT_MAIN_MENU);
2099 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2104 load_mission_load = time(NULL) - load_mission_load;
2106 // If this is a red alert mission in campaign mode, bash wingman status
2107 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2108 red_alert_bash_wingman_status();
2111 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2112 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2113 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2115 game_load_palette();
2119 load_post_level_init = time(NULL);
2120 game_post_level_init();
2121 load_post_level_init = time(NULL) - load_post_level_init;
2125 void Do_model_timings_test();
2126 Do_model_timings_test();
2130 load_mission_stuff = time(NULL);
2131 freespace_mission_load_stuff();
2132 load_mission_stuff = time(NULL) - load_mission_stuff;
2137 int Interface_framerate = 0;
2140 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2141 DCF_BOOL( show_framerate, Show_framerate )
2142 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2143 DCF_BOOL( show_target_weapons, Show_target_weapons )
2144 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2145 DCF_BOOL( sound, Sound_enabled )
2146 DCF_BOOL( zbuffer, game_zbuffer )
2147 DCF_BOOL( shield_system, New_shield_system )
2148 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2149 DCF_BOOL( player_attacking, Player_attacking_enabled )
2150 DCF_BOOL( show_waypoints, Show_waypoints )
2151 DCF_BOOL( show_area_effect, Show_area_effect )
2152 DCF_BOOL( show_net_stats, Show_net_stats )
2153 DCF_BOOL( log, Log_debug_output_to_file )
2154 DCF_BOOL( training_msg_method, Training_msg_method )
2155 DCF_BOOL( show_player_pos, Show_player_pos )
2156 DCF_BOOL(i_framerate, Interface_framerate )
2158 DCF(show_mem,"Toggles showing mem usage")
2161 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2162 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2163 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2164 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2170 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2172 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2173 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2177 DCF(show_cpu,"Toggles showing cpu usage")
2180 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2181 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2182 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2183 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2189 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2191 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2192 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2199 // AL 4-8-98: always allow players to display their framerate
2202 DCF_BOOL( show_framerate, Show_framerate )
2209 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2212 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2213 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2214 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2215 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2217 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" );
2218 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2220 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2223 DCF(palette_flash,"Toggles palette flash effect on/off")
2226 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2227 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2228 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2229 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2231 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2232 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2235 int Use_low_mem = 0;
2237 DCF(low_mem,"Uses low memory settings regardless of RAM")
2240 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2241 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2242 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2243 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2245 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2246 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2248 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2254 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2257 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2258 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2259 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2260 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2262 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2263 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2264 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2268 int Framerate_delay = 0;
2270 float Freespace_gamma = 1.0f;
2272 DCF(gamma,"Sets Gamma factor")
2275 dc_get_arg(ARG_FLOAT|ARG_NONE);
2276 if ( Dc_arg_type & ARG_FLOAT ) {
2277 Freespace_gamma = Dc_arg_float;
2279 dc_printf( "Gamma reset to 1.0f\n" );
2280 Freespace_gamma = 1.0f;
2282 if ( Freespace_gamma < 0.1f ) {
2283 Freespace_gamma = 0.1f;
2284 } else if ( Freespace_gamma > 5.0f ) {
2285 Freespace_gamma = 5.0f;
2287 gr_set_gamma(Freespace_gamma);
2289 char tmp_gamma_string[32];
2290 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2291 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2295 dc_printf( "Usage: gamma <float>\n" );
2296 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2297 Dc_status = 0; // don't print status if help is printed. Too messy.
2301 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2310 Game_current_mission_filename[0] = 0;
2312 // seed the random number generator
2313 Game_init_seed = time(NULL);
2314 srand( Game_init_seed );
2316 Framerate_delay = 0;
2322 extern void bm_init();
2328 // Initialize the timer before the os
2336 GetCurrentDirectory(1024, whee);
2339 getcwd (whee, 1024);
2342 strcat(whee, EXE_FNAME);
2344 //Initialize the libraries
2345 s1 = timer_get_milliseconds();
2346 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2349 e1 = timer_get_milliseconds();
2351 // time a bunch of cfopens
2353 s2 = timer_get_milliseconds();
2355 for(int idx=0; idx<10000; idx++){
2356 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2361 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2363 e2 = timer_get_milliseconds();
2366 if (Is_standalone) {
2367 std_init_standalone();
2369 os_init( Osreg_class_name, Osreg_app_name );
2370 os_set_title(Osreg_title);
2373 // initialize localization module. Make sure this is down AFTER initialzing OS.
2374 // int t1 = timer_get_milliseconds();
2375 lcl_init( detect_lang() );
2377 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2379 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2382 // verify that he has a valid weapons.tbl
2383 verify_weapons_tbl();
2386 // setup the default osreg values if they don't exist
2390 // Output version numbers to registry for auto patching purposes
2391 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2392 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2393 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2395 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2396 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2397 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2400 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2403 #if defined (PLAT_UNIX) && defined(RELEASE_REAL)
2404 // show the FPS counter if the config file says so
2405 Show_framerate = os_config_read_uint( NULL, NOX("ShowFPS"), 0 );
2408 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2409 Asteroids_enabled = 1;
2412 /////////////////////////////
2414 /////////////////////////////
2419 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2420 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2422 if (!stricmp(ptr, NOX("no sound"))) {
2423 Cmdline_freespace_no_sound = 1;
2425 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2427 } else if (!stricmp(ptr, NOX("EAX"))) {
2432 if (!Is_standalone) {
2433 snd_init(use_a3d, use_eax);
2435 /////////////////////////////
2437 /////////////////////////////
2439 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2442 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);
2444 // fire up the UpdateLauncher executable
2446 PROCESS_INFORMATION pi;
2448 memset( &si, 0, sizeof(STARTUPINFO) );
2451 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2452 NULL, // pointer to command line string
2453 NULL, // pointer to process security attributes
2454 NULL, // pointer to thread security attributes
2455 FALSE, // handle inheritance flag
2456 CREATE_DEFAULT_ERROR_MODE, // creation flags
2457 NULL, // pointer to new environment block
2458 NULL, // pointer to current directory name
2459 &si, // pointer to STARTUPINFO
2460 &pi // pointer to PROCESS_INFORMATION
2463 // If the Launcher could not be started up, let the user know
2465 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2474 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2476 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);
2484 // check for hi res pack file
2485 int has_sparky_hi = 0;
2487 // check if sparky_hi exists -- access mode 0 means does file exist
2488 #ifndef MAKE_FS1 // shoudn't have it so don't check
2491 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2494 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2498 // see if we've got 32 bit in the string
2499 if(strstr(ptr, "32 bit")){
2506 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2508 // always 640 for E3
2509 gr_init(GR_640, GR_GLIDE);
2511 // regular or hi-res ?
2513 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2515 if(strstr(ptr, NOX("(1024x768)"))){
2517 gr_init(GR_1024, GR_GLIDE);
2519 gr_init(GR_640, GR_GLIDE);
2522 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2524 // always 640 for E3
2526 gr_init(GR_640, GR_DIRECT3D, depth);
2528 // regular or hi-res ?
2530 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2532 if(strstr(ptr, NOX("(1024x768)"))){
2536 gr_init(GR_1024, GR_DIRECT3D, depth);
2540 gr_init(GR_640, GR_DIRECT3D, depth);
2546 if ( Use_fullscreen_at_startup && !Is_standalone) {
2547 gr_init(GR_640, GR_DIRECTDRAW);
2549 gr_init(GR_640, GR_SOFTWARE);
2552 if ( !Is_standalone ) {
2553 gr_init(GR_640, GR_DIRECTDRAW);
2555 gr_init(GR_640, GR_SOFTWARE);
2560 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2561 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2562 gr_init(GR_1024, GR_OPENGL);
2564 gr_init(GR_640, GR_OPENGL);
2568 gr_init(GR_640, GR_SOFTWARE);
2573 extern int Gr_inited;
2574 if(trying_d3d && !Gr_inited){
2576 extern char Device_init_error[512];
2577 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2586 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2587 Freespace_gamma = (float)atof(ptr);
2588 if ( Freespace_gamma == 0.0f ) {
2589 Freespace_gamma = 1.80f;
2590 } else if ( Freespace_gamma < 0.1f ) {
2591 Freespace_gamma = 0.1f;
2592 } else if ( Freespace_gamma > 5.0f ) {
2593 Freespace_gamma = 5.0f;
2595 char tmp_gamma_string[32];
2596 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2597 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2599 gr_set_gamma(Freespace_gamma);
2601 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2604 display_title_screen();
2608 // attempt to load up master tracker registry info (login and password)
2609 Multi_tracker_id = -1;
2611 // pxo login and password
2612 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2614 nprintf(("Network","Error reading in PXO login data\n"));
2615 strcpy(Multi_tracker_login,"");
2617 strcpy(Multi_tracker_login,ptr);
2619 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2621 nprintf(("Network","Error reading PXO password\n"));
2622 strcpy(Multi_tracker_passwd,"");
2624 strcpy(Multi_tracker_passwd,ptr);
2627 // pxo squad name and password
2628 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2630 nprintf(("Network","Error reading in PXO squad name\n"));
2631 strcpy(Multi_tracker_squad_name, "");
2633 strcpy(Multi_tracker_squad_name, ptr);
2636 // If less than 48MB of RAM, use low memory model.
2639 (Freespace_total_ram < 48*1024*1024) ||
2642 mprintf(( "Using normal memory settings...\n" ));
2643 bm_set_low_mem(1); // Use every other frame of bitmaps
2645 mprintf(( "Using high memory settings...\n" ));
2646 bm_set_low_mem(0); // Use all frames of bitmaps
2649 // load non-darkening pixel defs
2650 palman_load_pixels();
2652 // hud shield icon stuff
2653 hud_shield_game_init();
2655 control_config_common_init(); // sets up localization stuff in the control config
2661 gamesnd_parse_soundstbl();
2666 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2671 player_controls_init();
2674 //if(!Is_standalone){
2682 ship_init(); // read in ships.tbl
2684 mission_campaign_init(); // load in the default campaign
2686 // navmap_init(); // init the navigation map system
2687 context_help_init();
2688 techroom_intel_init(); // parse species.tbl, load intel info
2690 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2691 init_animating_pointer();
2693 mission_brief_common_init(); // Mark all the briefing structures as empty.
2694 gr_font_init(); // loads up all fonts
2696 neb2_init(); // fullneb stuff
2700 player_tips_init(); // helpful tips
2703 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2704 pilot_load_pic_list();
2705 pilot_load_squad_pic_list();
2707 load_animating_pointer(NOX("cursor"), 0, 0);
2709 // initialize alpha colors
2710 alpha_colors_init();
2713 // Game_music_paused = 0;
2720 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2721 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2723 mprintf(("cfile_init() took %d\n", e1 - s1));
2724 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2727 char transfer_text[128];
2729 float Start_time = 0.0f;
2731 float Framerate = 0.0f;
2733 float Timing_total = 0.0f;
2734 float Timing_render2 = 0.0f;
2735 float Timing_render3 = 0.0f;
2736 float Timing_flip = 0.0f;
2737 float Timing_clear = 0.0f;
2739 MONITOR(NumPolysDrawn);
2745 void game_get_framerate()
2747 char text[128] = "";
2749 if ( frame_int == -1 ) {
2751 for (i=0; i<FRAME_FILTER; i++ ) {
2752 frametimes[i] = 0.0f;
2757 frametotal -= frametimes[frame_int];
2758 frametotal += flFrametime;
2759 frametimes[frame_int] = flFrametime;
2760 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2762 if ( frametotal != 0.0 ) {
2763 if ( Framecount >= FRAME_FILTER )
2764 Framerate = FRAME_FILTER / frametotal;
2766 Framerate = Framecount / frametotal;
2767 sprintf( text, NOX("FPS: %.1f"), Framerate );
2769 sprintf( text, NOX("FPS: ?") );
2773 if (Show_framerate) {
2774 gr_set_color_fast(&HUD_color_debug);
2775 gr_string( 570, 2, text );
2779 void game_show_framerate()
2783 cur_time = f2fl(timer_get_approx_seconds());
2784 if (cur_time - Start_time > 30.0f) {
2785 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2786 Start_time += 1000.0f;
2789 //mprintf(( "%s\n", text ));
2792 if ( Debug_dump_frames )
2796 // possibly show control checking info
2797 control_check_indicate();
2799 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2800 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2801 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2802 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2805 if ( Show_cpu == 1 ) {
2810 dy = gr_get_font_height() + 1;
2812 gr_set_color_fast(&HUD_color_debug);
2816 extern int D3D_textures_in;
2817 extern int D3D_textures_in_frame;
2818 extern int Glide_textures_in;
2819 extern int Glide_textures_in_frame;
2820 extern int Glide_explosion_vram;
2821 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2823 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2825 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2829 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2831 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2833 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2835 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2837 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2842 extern int Num_pairs; // Number of object pairs that were checked.
2843 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2846 extern int Num_pairs_checked; // What percent of object pairs were checked.
2847 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2849 Num_pairs_checked = 0;
2853 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2856 if ( Timing_total > 0.01f ) {
2857 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2859 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2861 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2863 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2865 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2875 dy = gr_get_font_height() + 1;
2877 gr_set_color_fast(&HUD_color_debug);
2880 extern int TotalRam;
2881 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2886 extern int Model_ram;
2887 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2891 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2893 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2895 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2899 extern int D3D_textures_in;
2900 extern int Glide_textures_in;
2901 extern int Glide_textures_in_frame;
2902 extern int Glide_explosion_vram;
2903 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2905 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2907 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2914 if ( Show_player_pos ) {
2918 gr_printf(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.xyz.x), fl2i(Player_obj->pos.xyz.y), fl2i(Player_obj->pos.xyz.z));
2921 MONITOR_INC(NumPolys, modelstats_num_polys);
2922 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2923 MONITOR_INC(NumVerts, modelstats_num_verts );
2925 modelstats_num_polys = 0;
2926 modelstats_num_polys_drawn = 0;
2927 modelstats_num_verts = 0;
2928 modelstats_num_sortnorms = 0;
2932 void game_show_standalone_framerate()
2934 float frame_rate=30.0f;
2935 if ( frame_int == -1 ) {
2937 for (i=0; i<FRAME_FILTER; i++ ) {
2938 frametimes[i] = 0.0f;
2943 frametotal -= frametimes[frame_int];
2944 frametotal += flFrametime;
2945 frametimes[frame_int] = flFrametime;
2946 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2948 if ( frametotal != 0.0 ) {
2949 if ( Framecount >= FRAME_FILTER ){
2950 frame_rate = FRAME_FILTER / frametotal;
2952 frame_rate = Framecount / frametotal;
2955 std_set_standalone_fps(frame_rate);
2959 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2960 void game_show_time_left()
2964 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2965 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2966 // checking how much time is left
2968 if ( Mission_end_time == -1 ){
2972 diff = f2i(Mission_end_time - Missiontime);
2973 // be sure to bash to 0. diff could be negative on frame that we quit mission
2978 hud_set_default_color();
2979 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2982 //========================================================================================
2983 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2984 //========================================================================================
2988 DCF(ai_pause,"Pauses ai")
2991 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2992 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2993 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2994 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2997 obj_init_all_ships_physics();
3000 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
3001 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
3004 DCF(single_step,"Single steps the game")
3007 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3008 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
3009 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
3010 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
3012 last_single_step = 0; // Make so single step waits a frame before stepping
3015 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
3016 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
3019 DCF_BOOL(physics_pause, physics_paused)
3020 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
3021 DCF_BOOL(ai_firing, Ai_firing_enabled )
3023 // Create some simple aliases to these commands...
3024 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
3025 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
3026 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
3027 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
3028 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
3031 //========================================================================================
3032 //========================================================================================
3035 void game_training_pause_do()
3039 key = game_check_key();
3041 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
3048 void game_increase_skill_level()
3051 if (Game_skill_level >= NUM_SKILL_LEVELS){
3052 Game_skill_level = 0;
3056 int Player_died_time;
3058 int View_percent = 100;
3061 DCF(view, "Sets the percent of the 3d view to render.")
3064 dc_get_arg(ARG_INT);
3065 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
3066 View_percent = Dc_arg_int;
3068 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
3074 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
3078 dc_printf("View is set to %d%%\n", View_percent );
3083 // Set the clip region for the 3d rendering window
3084 void game_set_view_clip()
3086 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
3087 // Set the clip region for the letterbox "dead view"
3088 int yborder = gr_screen.max_h/4;
3090 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
3091 // J.S. I've changed my ways!! See the new "no constants" code!!!
3092 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
3094 // Set the clip region for normal view
3095 if ( View_percent >= 100 ) {
3098 int xborder, yborder;
3100 if ( View_percent < 5 ) {
3104 float fp = i2fl(View_percent)/100.0f;
3105 int fi = fl2i(fl_sqrt(fp)*100.0f);
3106 if ( fi > 100 ) fi=100;
3108 xborder = ( gr_screen.max_w*(100-fi) )/200;
3109 yborder = ( gr_screen.max_h*(100-fi) )/200;
3111 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
3117 void show_debug_stuff()
3120 int laser_count = 0, missile_count = 0;
3122 for (i=0; i<MAX_OBJECTS; i++) {
3123 if (Objects[i].type == OBJ_WEAPON){
3124 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
3126 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
3132 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
3135 extern int Tool_enabled;
3140 int tst_bitmap = -1;
3142 float tst_offset, tst_offset_total;
3145 void game_tst_frame_pre()
3153 g3_rotate_vertex(&v, &tst_pos);
3154 g3_project_vertex(&v);
3157 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
3161 // big ship? always tst
3163 // within 3000 meters
3164 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
3168 // within 300 meters
3169 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
3176 void game_tst_frame()
3186 tst_time = time(NULL);
3188 // load the tst bitmap
3189 switch((int)frand_range(0.0f, 3.0)){
3191 tst_bitmap = bm_load("ig_jim");
3193 mprintf(("TST 0\n"));
3197 tst_bitmap = bm_load("ig_kan");
3199 mprintf(("TST 1\n"));
3203 tst_bitmap = bm_load("ig_jim");
3205 mprintf(("TST 2\n"));
3209 tst_bitmap = bm_load("ig_kan");
3211 mprintf(("TST 3\n"));
3220 // get the tst bitmap dimensions
3222 bm_get_info(tst_bitmap, &w, &h);
3225 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3227 snd_play(&Snds[SND_VASUDAN_BUP]);
3229 // tst x and direction
3233 tst_offset_total = (float)w;
3234 tst_offset = (float)w;
3236 tst_x = (float)gr_screen.max_w;
3237 tst_offset_total = (float)-w;
3238 tst_offset = (float)w;
3246 float diff = (tst_offset_total / 0.5f) * flFrametime;
3252 tst_offset -= fl_abs(diff);
3253 } else if(tst_mode == 2){
3256 tst_offset -= fl_abs(diff);
3260 gr_set_bitmap(tst_bitmap);
3261 gr_bitmap((int)tst_x, (int)tst_y);
3264 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3268 // if we passed the switch point
3269 if(tst_offset <= 0.0f){
3274 tst_stamp = timestamp(1000);
3275 tst_offset = fl_abs(tst_offset_total);
3286 void game_tst_mark(object *objp, ship *shipp)
3295 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3298 sip = &Ship_info[shipp->ship_info_index];
3305 tst_pos = objp->pos;
3306 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3312 extern void render_shields();
3314 void player_repair_frame(float frametime)
3316 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3318 for(idx=0;idx<MAX_PLAYERS;idx++){
3321 np = &Net_players[idx];
3323 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)){
3325 // don't rearm/repair if the player is dead or dying/departing
3326 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3327 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3332 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3333 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3339 #define NUM_FRAMES_TEST 300
3340 #define NUM_MIXED_SOUNDS 16
3341 void do_timing_test(float flFrametime)
3343 static int framecount = 0;
3344 static int test_running = 0;
3345 static float test_time = 0.0f;
3347 static int snds[NUM_MIXED_SOUNDS];
3350 if ( test_running ) {
3352 test_time += flFrametime;
3353 if ( framecount >= NUM_FRAMES_TEST ) {
3355 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3356 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3361 if ( Test_begin == 1 ) {
3367 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3370 // start looping digital sounds
3371 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3372 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3379 DCF(dcf_fov, "Change the field of view")
3382 dc_get_arg(ARG_FLOAT|ARG_NONE);
3383 if ( Dc_arg_type & ARG_NONE ) {
3384 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3385 dc_printf( "Zoom factor reset\n" );
3387 if ( Dc_arg_type & ARG_FLOAT ) {
3388 if (Dc_arg_float < 0.25f) {
3389 Viewer_zoom = 0.25f;
3390 dc_printf("Zoom factor pinned at 0.25.\n");
3391 } else if (Dc_arg_float > 1.25f) {
3392 Viewer_zoom = 1.25f;
3393 dc_printf("Zoom factor pinned at 1.25.\n");
3395 Viewer_zoom = Dc_arg_float;
3401 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3404 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3408 DCF(framerate_cap, "Sets the framerate cap")
3411 dc_get_arg(ARG_INT);
3412 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3413 Framerate_cap = Dc_arg_int;
3415 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3421 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3422 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3423 dc_printf("[n] must be from 1 to 120.\n");
3427 if ( Framerate_cap )
3428 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3430 dc_printf("There is no framerate cap currently active.\n");
3434 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3435 int Show_viewing_from_self = 0;
3437 void say_view_target()
3439 object *view_target;
3441 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3442 view_target = &Objects[Player_ai->target_objnum];
3444 view_target = Player_obj;
3446 if (Game_mode & GM_DEAD) {
3447 if (Player_ai->target_objnum != -1)
3448 view_target = &Objects[Player_ai->target_objnum];
3451 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3452 if (view_target != Player_obj){
3454 char *view_target_name = NULL;
3455 switch(Objects[Player_ai->target_objnum].type) {
3457 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3460 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3461 Viewer_mode &= ~VM_OTHER_SHIP;
3463 case OBJ_JUMP_NODE: {
3464 char jump_node_name[128];
3465 strcpy(jump_node_name, XSTR( "jump node", 184));
3466 view_target_name = jump_node_name;
3467 Viewer_mode &= ~VM_OTHER_SHIP;
3476 if ( view_target_name ) {
3477 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3478 Show_viewing_from_self = 1;
3481 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3482 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3483 Show_viewing_from_self = 1;
3485 if (Show_viewing_from_self)
3486 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3491 Last_view_target = view_target;
3495 float Game_hit_x = 0.0f;
3496 float Game_hit_y = 0.0f;
3498 // Reset at the beginning of each frame
3499 void game_whack_reset()
3505 // Apply a 2d whack to the player
3506 void game_whack_apply( float x, float y )
3508 // Do some force feedback
3509 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3515 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3518 // call to apply a "shudder"
3519 void game_shudder_apply(int time, float intensity)
3521 Game_shudder_time = timestamp(time);
3522 Game_shudder_total = time;
3523 Game_shudder_intensity = intensity;
3526 #define FF_SCALE 10000
3527 void apply_hud_shake(matrix *eye_orient)
3529 if (Viewer_obj == Player_obj) {
3530 physics_info *pi = &Player_obj->phys_info;
3538 // Make eye shake due to afterburner
3539 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3542 dtime = timestamp_until(pi->afterburner_decay);
3546 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3547 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3550 // Make eye shake due to engine wash
3552 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3555 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3556 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3558 // get the intensity
3559 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3563 vm_vec_rand_vec_quick(&rand_vec);
3566 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3570 // make hud shake due to shuddering
3571 if(Game_shudder_time != -1){
3572 // if the timestamp has elapsed
3573 if(timestamp_elapsed(Game_shudder_time)){
3574 Game_shudder_time = -1;
3576 // otherwise apply some shudder
3580 dtime = timestamp_until(Game_shudder_time);
3584 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));
3585 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));
3590 vm_angles_2_matrix(&tm, &tangles);
3591 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3592 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3593 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3594 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3599 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3601 // Player's velocity just before he blew up. Used to keep camera target moving.
3602 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3604 // Set eye_pos and eye_orient based on view mode.
3605 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3609 static int last_Viewer_mode = 0;
3610 static int last_Game_mode = 0;
3611 static int last_Viewer_objnum = -1;
3613 // This code is supposed to detect camera "cuts"... like going between
3616 // determine if we need to regenerate the nebula
3617 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3618 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3619 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3620 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3621 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3622 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3623 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3624 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3625 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3628 // regenerate the nebula
3632 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3633 //mprintf(( "************** Camera cut! ************\n" ));
3634 last_Viewer_mode = Viewer_mode;
3635 last_Game_mode = Game_mode;
3637 // Camera moved. Tell stars & debris to not do blurring.
3643 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3644 player_display_packlock_view();
3647 game_set_view_clip();
3649 if (Game_mode & GM_DEAD) {
3650 vector vec_to_deader, view_pos;
3653 Viewer_mode |= VM_DEAD_VIEW;
3655 if (Player_ai->target_objnum != -1) {
3656 int view_from_player = 1;
3658 if (Viewer_mode & VM_OTHER_SHIP) {
3659 // View from target.
3660 Viewer_obj = &Objects[Player_ai->target_objnum];
3662 last_Viewer_objnum = Player_ai->target_objnum;
3664 if ( Viewer_obj->type == OBJ_SHIP ) {
3665 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3666 view_from_player = 0;
3669 last_Viewer_objnum = -1;
3672 if ( view_from_player ) {
3673 // View target from player ship.
3675 *eye_pos = Player_obj->pos;
3676 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3677 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3680 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3682 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3683 dist += flFrametime * 16.0f;
3685 vm_vec_scale(&vec_to_deader, -dist);
3686 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3688 view_pos = Player_obj->pos;
3690 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3691 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3692 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3693 Dead_player_last_vel = Player_obj->phys_info.vel;
3694 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.xyz.x, Player_obj->phys_info.vel.xyz.y, Player_obj->phys_info.vel.xyz.z));
3695 } else if (Player_ai->target_objnum != -1) {
3696 view_pos = Objects[Player_ai->target_objnum].pos;
3698 // Make camera follow explosion, but gradually slow down.
3699 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3700 view_pos = Player_obj->pos;
3701 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3702 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3705 *eye_pos = Dead_camera_pos;
3707 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3709 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3714 // if supernova shockwave
3715 if(supernova_camera_cut()){
3719 // call it dead view
3720 Viewer_mode |= VM_DEAD_VIEW;
3722 // set eye pos and orient
3723 supernova_set_view(eye_pos, eye_orient);
3725 // If already blown up, these other modes can override.
3726 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3727 Viewer_mode &= ~VM_DEAD_VIEW;
3729 Viewer_obj = Player_obj;
3731 if (Viewer_mode & VM_OTHER_SHIP) {
3732 if (Player_ai->target_objnum != -1){
3733 Viewer_obj = &Objects[Player_ai->target_objnum];
3734 last_Viewer_objnum = Player_ai->target_objnum;
3736 Viewer_mode &= ~VM_OTHER_SHIP;
3737 last_Viewer_objnum = -1;
3740 last_Viewer_objnum = -1;
3743 if (Viewer_mode & VM_EXTERNAL) {
3746 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3747 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3749 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3751 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3752 vm_vec_normalize(&eye_dir);
3753 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3756 // Modify the orientation based on head orientation.
3757 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3759 } else if ( Viewer_mode & VM_CHASE ) {
3762 if ( Viewer_obj->phys_info.speed < 0.1 )
3763 move_dir = Viewer_obj->orient.v.fvec;
3765 move_dir = Viewer_obj->phys_info.vel;
3766 vm_vec_normalize(&move_dir);
3769 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3770 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3771 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3772 vm_vec_normalize(&eye_dir);
3774 // JAS: I added the following code because if you slew up using
3775 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3776 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3777 // call because the up and the forward vector are the same. I fixed
3778 // it by adding in a fraction of the right vector all the time to the
3780 vector tmp_up = Viewer_obj->orient.v.uvec;
3781 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3783 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3786 // Modify the orientation based on head orientation.
3787 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3788 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3789 *eye_pos = Camera_pos;
3791 ship * shipp = &Ships[Player_obj->instance];
3793 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3794 vm_vec_normalize(&eye_dir);
3795 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3798 // get an eye position based upon the correct type of object
3799 switch(Viewer_obj->type){
3801 // make a call to get the eye point for the player object
3802 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3805 // make a call to get the eye point for the player object
3806 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3812 #ifdef JOHNS_DEBUG_CODE
3813 john_debug_stuff(&eye_pos, &eye_orient);
3819 apply_hud_shake(eye_orient);
3821 // setup neb2 rendering
3822 neb2_render_setup(eye_pos, eye_orient);
3826 extern void ai_debug_render_stuff();
3829 int Game_subspace_effect = 0;
3830 DCF_BOOL( subspace, Game_subspace_effect );
3832 // Does everything needed to render a frame
3833 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3837 g3_start_frame(game_zbuffer);
3838 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3840 // maybe offset the HUD (jitter stuff)
3841 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3842 HUD_set_offsets(Viewer_obj, !dont_offset);
3844 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3845 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3846 // must be done before ships are rendered
3847 if ( MULTIPLAYER_CLIENT ) {
3848 shield_point_multi_setup();
3851 if ( Game_subspace_effect ) {
3852 stars_draw(0,0,0,1);
3854 stars_draw(1,1,1,0);
3857 obj_render_all(obj_render);
3858 beam_render_all(); // render all beam weapons
3859 particle_render_all(); // render particles after everything else.
3860 trail_render_all(); // render missilie trails after everything else.
3861 mflash_render_all(); // render all muzzle flashes
3863 // Why do we not show the shield effect in these modes? Seems ok.
3864 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3868 // render nebula lightning
3871 // render local player nebula
3872 neb2_render_player();
3875 ai_debug_render_stuff();
3878 #ifndef RELEASE_REAL
3879 // game_framerate_check();
3883 extern void snd_spew_debug_info();
3884 snd_spew_debug_info();
3887 //================ END OF 3D RENDERING STUFF ====================
3891 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3892 hud_maybe_clear_head_area();
3893 anim_render_all(0, flFrametime);
3896 extern int Multi_display_netinfo;
3897 if(Multi_display_netinfo){
3898 extern void multi_display_netinfo();
3899 multi_display_netinfo();
3902 game_tst_frame_pre();
3905 do_timing_test(flFrametime);
3909 extern int OO_update_index;
3910 multi_rate_display(OO_update_index, 375, 0);
3915 extern void oo_display();
3922 //#define JOHNS_DEBUG_CODE 1
3924 #ifdef JOHNS_DEBUG_CODE
3925 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3927 //if ( keyd_pressed[KEY_LSHIFT] )
3929 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3931 model_subsystem *turret = tsys->system_info;
3933 if (turret->type == SUBSYSTEM_TURRET ) {
3934 vector v.fvec, v.uvec;
3935 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3937 ship_model_start(tobj);
3939 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3940 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3941 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3943 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3945 ship_model_stop(tobj);
3955 // following function for dumping frames for purposes of building trailers.
3958 // function to toggle state of dumping every frame into PCX when playing the game
3959 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3963 if ( Debug_dump_frames == 0 ) {
3965 Debug_dump_frames = 15;
3966 Debug_dump_trigger = 0;
3967 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3968 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3971 Debug_dump_frames = 0;
3972 Debug_dump_trigger = 0;
3973 gr_dump_frame_stop();
3974 dc_printf( "Frame dumping is now OFF\n" );
3980 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3984 if ( Debug_dump_frames == 0 ) {
3986 Debug_dump_frames = 15;
3987 Debug_dump_trigger = 1;
3988 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3989 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3992 Debug_dump_frames = 0;
3993 Debug_dump_trigger = 0;
3994 gr_dump_frame_stop();
3995 dc_printf( "Frame dumping is now OFF\n" );
4001 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
4005 if ( Debug_dump_frames == 0 ) {
4007 Debug_dump_frames = 30;
4008 Debug_dump_trigger = 0;
4009 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4010 dc_printf( "Frame dumping at 30 hz is now ON\n" );
4013 Debug_dump_frames = 0;
4014 Debug_dump_trigger = 0;
4015 gr_dump_frame_stop();
4016 dc_printf( "Frame dumping is now OFF\n" );
4022 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
4026 if ( Debug_dump_frames == 0 ) {
4028 Debug_dump_frames = 30;
4029 Debug_dump_trigger = 1;
4030 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4031 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
4034 Debug_dump_frames = 0;
4035 Debug_dump_trigger = 0;
4036 gr_dump_frame_stop();
4037 dc_printf( "Triggered frame dumping is now OFF\n" );
4043 void game_maybe_dump_frame()
4045 if ( !Debug_dump_frames ){
4049 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
4056 Debug_dump_frame_num++;
4062 extern int Player_dead_state;
4064 // Flip the page and time how long it took.
4065 void game_flip_page_and_time_it()
4070 t1 = timer_get_fixed_seconds();
4072 t2 = timer_get_fixed_seconds();
4075 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
4076 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
4083 void game_simulation_frame()
4085 // blow ships up in multiplayer dogfight
4086 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){
4087 // blow up all non-player ships
4088 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
4091 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
4093 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)){
4094 moveup = GET_NEXT(moveup);
4097 shipp = &Ships[Objects[moveup->objnum].instance];
4098 sip = &Ship_info[shipp->ship_info_index];
4100 // only blow up small ships
4101 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
4102 // function to simply explode a ship where it is currently at
4103 ship_self_destruct( &Objects[moveup->objnum] );
4106 moveup = GET_NEXT(moveup);
4112 // process AWACS stuff - do this first thing
4115 // single player, set Player hits_this_frame to 0
4116 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
4117 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
4118 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
4122 supernova_process();
4123 if(supernova_active() >= 5){
4127 // fire targeting lasers now so that
4128 // 1 - created this frame
4129 // 2 - collide this frame
4130 // 3 - render this frame
4131 // 4 - ignored and deleted next frame
4132 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
4134 ship_process_targeting_lasers();
4136 // do this here so that it works for multiplayer
4138 // get viewer direction
4139 int viewer_direction = PHYSICS_VIEWER_REAR;
4141 if(Viewer_mode == 0){
4142 viewer_direction = PHYSICS_VIEWER_FRONT;
4144 if(Viewer_mode & VM_PADLOCK_UP){
4145 viewer_direction = PHYSICS_VIEWER_UP;
4147 else if(Viewer_mode & VM_PADLOCK_REAR){
4148 viewer_direction = PHYSICS_VIEWER_REAR;
4150 else if(Viewer_mode & VM_PADLOCK_LEFT){
4151 viewer_direction = PHYSICS_VIEWER_LEFT;
4153 else if(Viewer_mode & VM_PADLOCK_RIGHT){
4154 viewer_direction = PHYSICS_VIEWER_RIGHT;
4157 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
4159 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
4162 #define VM_PADLOCK_UP (1 << 7)
4163 #define VM_PADLOCK_REAR (1 << 8)
4164 #define VM_PADLOCK_LEFT (1 << 9)
4165 #define VM_PADLOCK_RIGHT (1 << 10)
4167 // evaluate mission departures and arrivals before we process all objects.
4168 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
4170 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
4171 // ships/wing packets.
4172 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
4173 mission_parse_eval_stuff();
4176 // if we're an observer, move ourselves seperately from the standard physics
4177 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
4178 obj_observer_move(flFrametime);
4181 // move all the objects now
4182 obj_move_all(flFrametime);
4184 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
4185 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
4186 // ship_check_cargo_all();
4187 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4188 mission_eval_goals();
4192 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
4193 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4194 training_check_objectives();
4197 // do all interpolation now
4198 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
4199 // client side processing of warping in effect stages
4200 multi_do_client_warp(flFrametime);
4202 // client side movement of an observer
4203 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
4204 obj_observer_move(flFrametime);
4207 // move all objects - does interpolation now as well
4208 obj_move_all(flFrametime);
4211 // only process the message queue when the player is "in" the game
4212 if ( !Pre_player_entry ){
4213 message_queue_process(); // process any messages send to the player
4216 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4217 message_maybe_distort(); // maybe distort incoming message if comms damaged
4218 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4219 player_process_pending_praise(); // maybe send off a delayed praise message to the player
4220 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4223 if(!(Game_mode & GM_STANDALONE_SERVER)){
4224 // process some stuff every frame (before frame is rendered)
4225 emp_process_local();
4227 hud_update_frame(); // update hud systems
4229 if (!physics_paused) {
4230 // Move particle system
4231 particle_move_all(flFrametime);
4233 // Move missile trails
4234 trail_move_all(flFrametime);
4236 // process muzzle flashes
4237 mflash_process_all();
4239 // Flash the gun flashes
4240 shipfx_flash_do_frame(flFrametime);
4242 shockwave_move_all(flFrametime); // update all the shockwaves
4245 // subspace missile strikes
4248 obj_snd_do_frame(); // update the object-linked persistant sounds
4249 game_maybe_update_sound_environment();
4250 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4252 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4254 if ( Game_subspace_effect ) {
4255 game_start_subspace_ambient_sound();
4261 // Maybe render and process the dead-popup
4262 void game_maybe_do_dead_popup(float frametime)
4264 if ( popupdead_is_active() ) {
4266 int choice = popupdead_do_frame(frametime);
4268 if ( Game_mode & GM_NORMAL ) {
4272 if(game_do_cd_mission_check(Game_current_mission_filename)){
4273 gameseq_post_event(GS_EVENT_ENTER_GAME);
4275 gameseq_post_event(GS_EVENT_MAIN_MENU);
4280 gameseq_post_event(GS_EVENT_END_GAME);
4285 if(game_do_cd_mission_check(Game_current_mission_filename)){
4286 gameseq_post_event(GS_EVENT_START_GAME);
4288 gameseq_post_event(GS_EVENT_MAIN_MENU);
4292 // this should only happen during a red alert mission
4295 Assert(The_mission.red_alert);
4296 if(!The_mission.red_alert){
4298 if(game_do_cd_mission_check(Game_current_mission_filename)){
4299 gameseq_post_event(GS_EVENT_START_GAME);
4301 gameseq_post_event(GS_EVENT_MAIN_MENU);
4306 // choose the previous mission
4307 mission_campaign_previous_mission();
4309 if(game_do_cd_mission_check(Game_current_mission_filename)){
4310 gameseq_post_event(GS_EVENT_START_GAME);
4312 gameseq_post_event(GS_EVENT_MAIN_MENU);
4323 case POPUPDEAD_DO_MAIN_HALL:
4324 multi_quit_game(PROMPT_NONE,-1);
4327 case POPUPDEAD_DO_RESPAWN:
4328 multi_respawn_normal();
4329 event_music_player_respawn();
4332 case POPUPDEAD_DO_OBSERVER:
4333 multi_respawn_observer();
4334 event_music_player_respawn_as_observer();
4343 if ( leave_popup ) {
4349 // returns true if player is actually in a game_play stats
4350 int game_actually_playing()
4354 state = gameseq_get_state();
4355 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4361 // Draw the 2D HUD gauges
4362 void game_render_hud_2d()
4364 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4368 HUD_render_2d(flFrametime);
4372 // Draw the 3D-dependant HUD gauges
4373 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4375 g3_start_frame(0); // 0 = turn zbuffering off
4376 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4378 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4379 HUD_render_3d(flFrametime);
4383 game_sunspot_process(flFrametime);
4385 // Diminish the palette effect
4386 game_flash_diminish(flFrametime);
4394 int actually_playing;
4395 fix total_time1, total_time2;
4396 fix render2_time1=0, render2_time2=0;
4397 fix render3_time1=0, render3_time2=0;
4398 fix flip_time1=0, flip_time2=0;
4399 fix clear_time1=0, clear_time2=0;
4405 if (Framerate_delay) {
4406 int start_time = timer_get_milliseconds();
4407 while (timer_get_milliseconds() < start_time + Framerate_delay)
4413 demo_do_frame_start();
4415 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4420 // start timing frame
4421 timing_frame_start();
4423 total_time1 = timer_get_fixed_seconds();
4425 // var to hold which state we are in
4426 actually_playing = game_actually_playing();
4428 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4429 if (!(Game_mode & GM_STANDALONE_SERVER)){
4430 Assert( OBJ_INDEX(Player_obj) >= 0 );
4434 if (Missiontime > Entry_delay_time){
4435 Pre_player_entry = 0;
4437 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4440 // Note: These are done even before the player enters, else buffers can overflow.
4441 if (! (Game_mode & GM_STANDALONE_SERVER)){
4445 shield_frame_init();
4447 if ( Player->control_mode != PCM_NORMAL )
4450 if ( !Pre_player_entry && actually_playing ) {
4451 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4453 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4454 game_process_keys();
4456 // don't read flying controls if we're playing a demo back
4457 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4458 read_player_controls( Player_obj, flFrametime);
4462 // if we're not the master, we may have to send the server-critical ship status button_info bits
4463 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4464 multi_maybe_send_ship_status();
4469 // Reset the whack stuff
4472 // These two lines must be outside of Pre_player_entry code,
4473 // otherwise too many lights are added.
4476 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4480 game_simulation_frame();
4482 // if not actually in a game play state, then return. This condition could only be true in
4483 // a multiplayer game.
4484 if ( !actually_playing ) {
4485 Assert( Game_mode & GM_MULTIPLAYER );
4489 if (!Pre_player_entry) {
4490 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4491 clear_time1 = timer_get_fixed_seconds();
4492 // clear the screen to black
4494 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4498 clear_time2 = timer_get_fixed_seconds();
4499 render3_time1 = timer_get_fixed_seconds();
4500 game_render_frame_setup(&eye_pos, &eye_orient);
4501 game_render_frame( &eye_pos, &eye_orient );
4503 // save the eye position and orientation
4504 if ( Game_mode & GM_MULTIPLAYER ) {
4505 Net_player->s_info.eye_pos = eye_pos;
4506 Net_player->s_info.eye_orient = eye_orient;
4509 hud_show_target_model();
4511 // check to see if we should display the death died popup
4512 if(Game_mode & GM_DEAD_BLEW_UP){
4513 if(Game_mode & GM_MULTIPLAYER){
4514 // catch the situation where we're supposed to be warping out on this transition
4515 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4516 gameseq_post_event(GS_EVENT_DEBRIEF);
4517 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4518 Player_died_popup_wait = -1;
4522 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4523 Player_died_popup_wait = -1;
4529 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4530 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4531 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4532 if(!popupdead_is_active()){
4536 Player_multi_died_check = -1;
4540 render3_time2 = timer_get_fixed_seconds();
4541 render2_time1 = timer_get_fixed_seconds();
4544 game_get_framerate();
4545 game_show_framerate();
4547 game_show_time_left();
4549 // Draw the 2D HUD gauges
4550 if(supernova_active() < 3){
4551 game_render_hud_2d();
4554 game_set_view_clip();
4556 // Draw 3D HUD gauges
4557 game_render_hud_3d(&eye_pos, &eye_orient);
4561 render2_time2 = timer_get_fixed_seconds();
4563 // maybe render and process the dead popup
4564 game_maybe_do_dead_popup(flFrametime);
4566 // start timing frame
4567 timing_frame_stop();
4568 // timing_display(30, 10);
4570 // If a regular popup is active, don't flip (popup code flips)
4571 if( !popup_running_state() ){
4572 flip_time1 = timer_get_fixed_seconds();
4573 game_flip_page_and_time_it();
4574 flip_time2 = timer_get_fixed_seconds();
4578 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4581 game_show_standalone_framerate();
4585 game_do_training_checks();
4588 // process lightning (nebula only)
4591 total_time2 = timer_get_fixed_seconds();
4593 // Got some timing numbers
4594 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4595 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4596 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4597 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4598 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4601 demo_do_frame_end();
4603 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4609 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4610 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4611 // died. This resulted in screwed up death sequences.
4613 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4614 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4615 static int timer_paused=0;
4616 #if defined(TIMER_TEST) && !defined(NDEBUG)
4617 static int stop_count,start_count;
4618 static int time_stopped,time_started;
4620 int saved_timestamp_ticker = -1;
4622 void game_reset_time()
4624 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4628 // Last_time = timer_get_fixed_seconds();
4634 void game_stop_time()
4636 if (timer_paused==0) {
4638 time = timer_get_fixed_seconds();
4639 // Save how much time progressed so far in the frame so we can
4640 // use it when we unpause.
4641 Last_delta_time = time - Last_time;
4643 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4644 if (Last_delta_time < 0) {
4645 #if defined(TIMER_TEST) && !defined(NDEBUG)
4646 Int3(); //get Matt!!!!
4648 Last_delta_time = 0;
4650 #if defined(TIMER_TEST) && !defined(NDEBUG)
4651 time_stopped = time;
4654 // Stop the timer_tick stuff...
4655 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4656 saved_timestamp_ticker = timestamp_ticker;
4660 #if defined(TIMER_TEST) && !defined(NDEBUG)
4665 void game_start_time()
4668 Assert(timer_paused >= 0);
4669 if (timer_paused==0) {
4671 time = timer_get_fixed_seconds();
4672 #if defined(TIMER_TEST) && !defined(NDEBUG)
4674 Int3(); //get Matt!!!!
4677 // Take current time, and set it backwards to account for time
4678 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4679 // will be correct when it goes to calculate the frametime next
4681 Last_time = time - Last_delta_time;
4682 #if defined(TIMER_TEST) && !defined(NDEBUG)
4683 time_started = time;
4686 // Restore the timer_tick stuff...
4687 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4688 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4689 timestamp_ticker = saved_timestamp_ticker;
4690 saved_timestamp_ticker = -1;
4693 #if defined(TIMER_TEST) && !defined(NDEBUG)
4699 void game_set_frametime(int state)
4702 float frame_cap_diff;
4704 thistime = timer_get_fixed_seconds();
4706 if ( Last_time == 0 )
4707 Frametime = F1_0 / 30;
4709 Frametime = thistime - Last_time;
4711 // Frametime = F1_0 / 30;
4713 fix debug_frametime = Frametime; // Just used to display frametime.
4715 // If player hasn't entered mission yet, make frame take 1/4 second.
4716 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4719 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4721 fix frame_speed = F1_0 / Debug_dump_frames;
4723 if (Frametime > frame_speed ){
4724 nprintf(("warning","slow frame: %x\n",Frametime));
4727 thistime = timer_get_fixed_seconds();
4728 Frametime = thistime - Last_time;
4729 } while (Frametime < frame_speed );
4731 Frametime = frame_speed;
4735 Assert( Framerate_cap > 0 );
4737 // Cap the framerate so it doesn't get too high.
4741 cap = F1_0/Framerate_cap;
4742 if (Frametime < cap) {
4743 thistime = cap - Frametime;
4744 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4745 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4747 thistime = timer_get_fixed_seconds();
4751 if((Game_mode & GM_STANDALONE_SERVER) &&
4752 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4754 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4755 Sleep((DWORD)(frame_cap_diff*1000));
4757 thistime += fl2f((frame_cap_diff));
4759 Frametime = thistime - Last_time;
4762 // If framerate is too low, cap it.
4763 if (Frametime > MAX_FRAMETIME) {
4765 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4767 // to remove warnings in release build
4768 debug_frametime = fl2f(flFrametime);
4770 Frametime = MAX_FRAMETIME;
4773 Frametime = fixmul(Frametime, Game_time_compression);
4775 Last_time = thistime;
4776 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4778 flFrametime = f2fl(Frametime);
4779 //if(!(Game_mode & GM_PLAYING_DEMO)){
4780 timestamp_inc(flFrametime);
4782 /* if ((Framecount > 0) && (Framecount < 10)) {
4783 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4788 // This is called from game_do_frame(), and from navmap_do_frame()
4789 void game_update_missiontime()
4791 // TODO JAS: Put in if and move this into game_set_frametime,
4792 // fix navmap to call game_stop/start_time
4793 //if ( !timer_paused )
4794 Missiontime += Frametime;
4797 void game_do_frame()
4799 game_set_frametime(GS_STATE_GAME_PLAY);
4800 game_update_missiontime();
4802 if (Game_mode & GM_STANDALONE_SERVER) {
4803 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4806 if ( game_single_step && (last_single_step == game_single_step) ) {
4807 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4808 while( key_checkch() == 0 )
4810 os_set_title( XSTR( "FreeSpace", 171) );
4811 Last_time = timer_get_fixed_seconds();
4814 last_single_step = game_single_step;
4816 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4817 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4821 Keep_mouse_centered = 0;
4822 monitor_update(); // Update monitor variables
4825 void multi_maybe_do_frame()
4827 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4832 int Joymouse_button_status = 0;
4834 // Flush all input devices
4842 Joymouse_button_status = 0;
4844 //mprintf(("Game flush!\n" ));
4847 // function for multiplayer only which calls game_do_state_common() when running the
4849 void game_do_dc_networking()
4851 Assert( Game_mode & GM_MULTIPLAYER );
4853 game_do_state_common( gameseq_get_state() );
4856 // Call this whenever in a loop, or when you need to check for a keystroke.
4857 int game_check_key()
4863 // convert keypad enter to normal enter
4864 if ((k & KEY_MASK) == KEY_PADENTER)
4865 k = (k & ~KEY_MASK) | KEY_ENTER;
4870 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4872 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4873 static int Demo_show_trailer_timestamp = 0;
4875 void demo_reset_trailer_timer()
4877 Demo_show_trailer_timestamp = timer_get_milliseconds();
4880 void demo_maybe_show_trailer(int k)
4883 // if key pressed, reset demo trailer timer
4885 demo_reset_trailer_timer();
4889 // if mouse moved, reset demo trailer timer
4892 mouse_get_delta(&dx, &dy);
4893 if ( (dx > 0) || (dy > 0) ) {
4894 demo_reset_trailer_timer();
4898 // if joystick has moved, reset demo trailer timer
4901 joy_get_delta(&dx, &dy);
4902 if ( (dx > 0) || (dy > 0) ) {
4903 demo_reset_trailer_timer();
4907 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4908 // the low-level code. Ugly, I know... but was the simplest and most
4911 // if 30 seconds since last demo trailer time reset, launch movie
4912 if ( os_foreground() ) {
4913 int now = timer_get_milliseconds();
4914 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4915 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4917 movie_play( NOX("fstrailer2.mve") );
4918 demo_reset_trailer_timer();
4926 // same as game_check_key(), except this is used while actually in the game. Since there
4927 // generally are differences between game control keys and general UI keys, makes sense to
4928 // have seperate functions for each case. If you are not checking a game control while in a
4929 // mission, you should probably be using game_check_key() instead.
4934 if (!os_foreground()) {
4939 // If we're in a single player game, pause it.
4940 if (!(Game_mode & GM_MULTIPLAYER)){
4941 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4942 game_process_pause_key();
4949 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4950 demo_maybe_show_trailer(k);
4953 // Move the mouse cursor with the joystick.
4954 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4955 // Move the mouse cursor with the joystick
4959 joy_get_pos( &jx, &jy, &jz, &jr );
4961 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4962 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4965 mouse_get_real_pos( &mx, &my );
4966 mouse_set_pos( mx+dx, my+dy );
4971 m = mouse_down(MOUSE_LEFT_BUTTON);
4973 if ( j != Joymouse_button_status ) {
4974 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4975 Joymouse_button_status = j;
4977 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4978 } else if ( (!j) && (m) ) {
4979 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4984 // if we should be ignoring keys because of some multiplayer situations
4985 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4989 // If a popup is running, don't process all the Fn keys
4990 if( popup_active() ) {
4994 state = gameseq_get_state();
4996 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4999 case KEY_DEBUGGED + KEY_BACKSP:
5004 launch_context_help();
5009 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
5011 // don't allow f2 while warping out in multiplayer
5012 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
5017 case GS_STATE_INITIAL_PLAYER_SELECT:
5018 case GS_STATE_OPTIONS_MENU:
5019 case GS_STATE_HUD_CONFIG:
5020 case GS_STATE_CONTROL_CONFIG:
5021 case GS_STATE_DEATH_DIED:
5022 case GS_STATE_DEATH_BLEW_UP:
5023 case GS_STATE_VIEW_MEDALS:
5027 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
5034 // hotkey selection screen -- only valid from briefing and beyond.
5036 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
5037 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) ) {
5038 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
5044 case KEY_DEBUGGED + KEY_F3:
5045 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
5048 case KEY_DEBUGGED + KEY_F4:
5049 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
5053 if(Game_mode & GM_MULTIPLAYER){
5054 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
5055 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5059 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
5060 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5066 case KEY_ESC | KEY_SHIFTED:
5067 // make sure to quit properly out of multiplayer
5068 if(Game_mode & GM_MULTIPLAYER){
5069 multi_quit_game(PROMPT_NONE);
5072 gameseq_post_event( GS_EVENT_QUIT_GAME );
5077 case KEY_DEBUGGED + KEY_P:
5080 case KEY_PRINT_SCRN:
5082 static int counter = 0;
5087 sprintf( tmp_name, NOX("screen%02d"), counter );
5089 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
5090 gr_print_screen(tmp_name);
5098 case KEY_SHIFTED | KEY_ENTER: {
5100 #if !defined(NDEBUG)
5102 if ( Game_mode & GM_NORMAL ){
5106 // if we're in multiplayer mode, do some special networking
5107 if(Game_mode & GM_MULTIPLAYER){
5108 debug_console(game_do_dc_networking);
5115 if ( Game_mode & GM_NORMAL )
5129 gameseq_post_event(GS_EVENT_QUIT_GAME);
5132 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
5135 void camera_set_position( vector *pos )
5140 void camera_set_orient( matrix *orient )
5142 Camera_orient = *orient;
5145 void camera_set_velocity( vector *vel, int instantaneous )
5147 Camera_desired_velocity.xyz.x = 0.0f;
5148 Camera_desired_velocity.xyz.y = 0.0f;
5149 Camera_desired_velocity.xyz.z = 0.0f;
5151 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
5152 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
5153 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
5155 if ( instantaneous ) {
5156 Camera_velocity = Camera_desired_velocity;
5164 vector new_vel, delta_pos;
5166 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
5167 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
5168 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
5170 Camera_velocity = new_vel;
5172 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
5174 vm_vec_add2( &Camera_pos, &delta_pos );
5176 float ot = Camera_time+0.0f;
5178 Camera_time += flFrametime;
5180 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
5183 tmp.xyz.z = 4.739f; // always go this fast forward.
5185 // pick x and y velocities so they are always on a
5186 // circle with a 25 m radius.
5188 float tmp_angle = frand()*PI2;
5190 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
5191 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
5193 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
5195 //mprintf(( "Changing velocity!\n" ));
5196 camera_set_velocity( &tmp, 0 );
5199 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
5200 vector tmp = { 0.0f, 0.0f, 0.0f };
5201 camera_set_velocity( &tmp, 0 );
5206 void end_demo_campaign_do()
5208 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5209 // show upsell screens
5210 demo_upsell_show_screens();
5211 #elif defined(OEM_BUILD)
5212 // show oem upsell screens
5213 oem_upsell_show_screens();
5216 // drop into main hall
5217 gameseq_post_event( GS_EVENT_MAIN_MENU );
5220 // All code to process events. This is the only place
5221 // that you should change the state of the game.
5222 void game_process_event( int current_state, int event )
5224 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5227 case GS_EVENT_SIMULATOR_ROOM:
5228 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5231 case GS_EVENT_MAIN_MENU:
5232 gameseq_set_state(GS_STATE_MAIN_MENU);
5235 case GS_EVENT_OPTIONS_MENU:
5236 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5239 case GS_EVENT_BARRACKS_MENU:
5240 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5243 case GS_EVENT_TECH_MENU:
5244 gameseq_set_state(GS_STATE_TECH_MENU);
5247 case GS_EVENT_TRAINING_MENU:
5248 gameseq_set_state(GS_STATE_TRAINING_MENU);
5251 case GS_EVENT_START_GAME:
5252 Select_default_ship = 0;
5253 Player_multi_died_check = -1;
5254 gameseq_set_state(GS_STATE_CMD_BRIEF);
5257 case GS_EVENT_START_BRIEFING:
5258 gameseq_set_state(GS_STATE_BRIEFING);
5261 case GS_EVENT_DEBRIEF:
5262 // did we end the campaign in the main freespace 2 single player campaign?
5264 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace")) {
5266 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5268 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5270 gameseq_set_state(GS_STATE_DEBRIEF);
5273 Player_multi_died_check = -1;
5276 case GS_EVENT_SHIP_SELECTION:
5277 gameseq_set_state( GS_STATE_SHIP_SELECT );
5280 case GS_EVENT_WEAPON_SELECTION:
5281 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5284 case GS_EVENT_ENTER_GAME:
5286 // maybe start recording a demo
5288 demo_start_record("test.fsd");
5292 if (Game_mode & GM_MULTIPLAYER) {
5293 // if we're respawning, make sure we change the view mode so that the hud shows up
5294 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5298 gameseq_set_state(GS_STATE_GAME_PLAY);
5300 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5303 Player_multi_died_check = -1;
5305 // clear multiplayer button info
5306 extern button_info Multi_ship_status_bi;
5307 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5309 Start_time = f2fl(timer_get_approx_seconds());
5311 mprintf(("Entering game at time = %7.3f\n", Start_time));
5315 case GS_EVENT_START_GAME_QUICK:
5316 Select_default_ship = 1;
5317 gameseq_post_event(GS_EVENT_ENTER_GAME);
5321 case GS_EVENT_END_GAME:
5322 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5323 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5324 gameseq_set_state(GS_STATE_MAIN_MENU);
5329 Player_multi_died_check = -1;
5332 case GS_EVENT_QUIT_GAME:
5333 main_hall_stop_music();
5334 main_hall_stop_ambient();
5335 gameseq_set_state(GS_STATE_QUIT_GAME);
5337 Player_multi_died_check = -1;
5340 case GS_EVENT_GAMEPLAY_HELP:
5341 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5344 case GS_EVENT_PAUSE_GAME:
5345 gameseq_push_state(GS_STATE_GAME_PAUSED);
5348 case GS_EVENT_DEBUG_PAUSE_GAME:
5349 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5352 case GS_EVENT_TRAINING_PAUSE:
5353 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5356 case GS_EVENT_PREVIOUS_STATE:
5357 gameseq_pop_state();
5360 case GS_EVENT_TOGGLE_FULLSCREEN:
5361 #ifndef HARDWARE_ONLY
5363 if ( gr_screen.mode == GR_SOFTWARE ) {
5364 gr_init( GR_640, GR_DIRECTDRAW );
5365 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5366 gr_init( GR_640, GR_SOFTWARE );
5372 case GS_EVENT_TOGGLE_GLIDE:
5374 if ( gr_screen.mode != GR_GLIDE ) {
5375 gr_init( GR_640, GR_GLIDE );
5377 gr_init( GR_640, GR_SOFTWARE );
5382 case GS_EVENT_LOAD_MISSION_MENU:
5383 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5386 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5387 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5390 case GS_EVENT_HUD_CONFIG:
5391 gameseq_push_state( GS_STATE_HUD_CONFIG );
5394 case GS_EVENT_CONTROL_CONFIG:
5395 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5398 case GS_EVENT_DEATH_DIED:
5399 gameseq_set_state( GS_STATE_DEATH_DIED );
5402 case GS_EVENT_DEATH_BLEW_UP:
5403 if ( current_state == GS_STATE_DEATH_DIED ) {
5404 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5405 event_music_player_death();
5407 // multiplayer clients set their extra check here
5408 if(Game_mode & GM_MULTIPLAYER){
5409 // set the multi died absolute last chance check
5410 Player_multi_died_check = time(NULL);
5413 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5417 case GS_EVENT_NEW_CAMPAIGN:
5418 if (!mission_load_up_campaign()){
5419 readyroom_continue_campaign();
5422 Player_multi_died_check = -1;
5425 case GS_EVENT_CAMPAIGN_CHEAT:
5426 if (!mission_load_up_campaign()){
5428 // bash campaign value
5429 extern char Main_hall_campaign_cheat[512];
5432 // look for the mission
5433 for(idx=0; idx<Campaign.num_missions; idx++){
5434 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5435 Campaign.next_mission = idx;
5436 Campaign.prev_mission = idx - 1;
5443 readyroom_continue_campaign();
5446 Player_multi_died_check = -1;
5449 case GS_EVENT_CAMPAIGN_ROOM:
5450 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5453 case GS_EVENT_CMD_BRIEF:
5454 gameseq_set_state(GS_STATE_CMD_BRIEF);
5457 case GS_EVENT_RED_ALERT:
5458 gameseq_set_state(GS_STATE_RED_ALERT);
5461 case GS_EVENT_CREDITS:
5462 gameseq_set_state( GS_STATE_CREDITS );
5465 case GS_EVENT_VIEW_MEDALS:
5466 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5469 case GS_EVENT_SHOW_GOALS:
5470 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5473 case GS_EVENT_HOTKEY_SCREEN:
5474 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5477 // multiplayer stuff follow these comments
5479 case GS_EVENT_MULTI_JOIN_GAME:
5480 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5483 case GS_EVENT_MULTI_HOST_SETUP:
5484 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5487 case GS_EVENT_MULTI_CLIENT_SETUP:
5488 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5491 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5492 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5495 case GS_EVENT_MULTI_STD_WAIT:
5496 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5499 case GS_EVENT_STANDALONE_MAIN:
5500 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5503 case GS_EVENT_MULTI_PAUSE:
5504 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5507 case GS_EVENT_INGAME_PRE_JOIN:
5508 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5511 case GS_EVENT_EVENT_DEBUG:
5512 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5515 // Start a warpout where player automatically goes 70 no matter what
5516 // and can't cancel out of it.
5517 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5518 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5520 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5521 Player->saved_viewer_mode = Viewer_mode;
5522 Player->control_mode = PCM_WARPOUT_STAGE1;
5523 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5524 Warpout_time = 0.0f; // Start timer!
5527 case GS_EVENT_PLAYER_WARPOUT_START:
5528 if ( Player->control_mode != PCM_NORMAL ) {
5529 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5531 Player->saved_viewer_mode = Viewer_mode;
5532 Player->control_mode = PCM_WARPOUT_STAGE1;
5533 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5534 Warpout_time = 0.0f; // Start timer!
5535 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5539 case GS_EVENT_PLAYER_WARPOUT_STOP:
5540 if ( Player->control_mode != PCM_NORMAL ) {
5541 if ( !Warpout_forced ) { // cannot cancel forced warpout
5542 Player->control_mode = PCM_NORMAL;
5543 Viewer_mode = Player->saved_viewer_mode;
5544 hud_subspace_notify_abort();
5545 mprintf(( "Player put back to normal mode.\n" ));
5546 if ( Warpout_sound > -1 ) {
5547 snd_stop( Warpout_sound );
5554 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5555 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5556 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5557 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5559 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5560 shipfx_warpout_start( Player_obj );
5561 Player->control_mode = PCM_WARPOUT_STAGE2;
5562 Player->saved_viewer_mode = Viewer_mode;
5563 Viewer_mode |= VM_WARP_CHASE;
5565 vector tmp = Player_obj->pos;
5567 ship_get_eye( &tmp, &tmp_m, Player_obj );
5568 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5569 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5570 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5572 camera_set_position( &tmp );
5573 camera_set_orient( &Player_obj->orient );
5574 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5576 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5577 camera_set_velocity( &tmp_vel, 1);
5581 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5582 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5583 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5584 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5586 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5587 Player->control_mode = PCM_WARPOUT_STAGE3;
5591 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5592 mprintf(( "Player warped out. Going to debriefing!\n" ));
5593 Player->control_mode = PCM_NORMAL;
5594 Viewer_mode = Player->saved_viewer_mode;
5597 // we have a special debriefing screen for multiplayer furballs
5598 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5599 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5601 // do the normal debriefing for all other situations
5603 gameseq_post_event(GS_EVENT_DEBRIEF);
5607 case GS_EVENT_STANDALONE_POSTGAME:
5608 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5611 case GS_EVENT_INITIAL_PLAYER_SELECT:
5612 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5615 case GS_EVENT_GAME_INIT:
5616 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5617 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5619 // see if the command line option has been set to use the last pilot, and act acoordingly
5620 if( player_select_get_last_pilot() ) {
5621 // always enter the main menu -- do the automatic network startup stuff elsewhere
5622 // so that we still have valid checks for networking modes, etc.
5623 gameseq_set_state(GS_STATE_MAIN_MENU);
5625 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5630 case GS_EVENT_MULTI_MISSION_SYNC:
5631 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5634 case GS_EVENT_MULTI_START_GAME:
5635 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5638 case GS_EVENT_MULTI_HOST_OPTIONS:
5639 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5642 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5643 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5646 case GS_EVENT_TEAM_SELECT:
5647 gameseq_set_state(GS_STATE_TEAM_SELECT);
5650 case GS_EVENT_END_CAMPAIGN:
5651 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5654 case GS_EVENT_END_DEMO:
5655 gameseq_set_state(GS_STATE_END_DEMO);
5658 case GS_EVENT_LOOP_BRIEF:
5659 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5668 // Called when a state is being left.
5669 // The current state is still at old_state, but as soon as
5670 // this function leaves, then the current state will become
5671 // new state. You should never try to change the state
5672 // in here... if you think you need to, you probably really
5673 // need to post an event, not change the state.
5674 void game_leave_state( int old_state, int new_state )
5676 int end_mission = 1;
5678 switch (new_state) {
5679 case GS_STATE_GAME_PAUSED:
5680 case GS_STATE_DEBUG_PAUSED:
5681 case GS_STATE_OPTIONS_MENU:
5682 case GS_STATE_CONTROL_CONFIG:
5683 case GS_STATE_MISSION_LOG_SCROLLBACK:
5684 case GS_STATE_DEATH_DIED:
5685 case GS_STATE_SHOW_GOALS:
5686 case GS_STATE_HOTKEY_SCREEN:
5687 case GS_STATE_MULTI_PAUSED:
5688 case GS_STATE_TRAINING_PAUSED:
5689 case GS_STATE_EVENT_DEBUG:
5690 case GS_STATE_GAMEPLAY_HELP:
5691 end_mission = 0; // these events shouldn't end a mission
5695 switch (old_state) {
5696 case GS_STATE_BRIEFING:
5697 brief_stop_voices();
5698 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5699 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5700 && (new_state != GS_STATE_TEAM_SELECT) ){
5701 common_select_close();
5702 if ( new_state == GS_STATE_MAIN_MENU ) {
5703 freespace_stop_mission();
5707 // COMMAND LINE OPTION
5708 if (Cmdline_multi_stream_chat_to_file){
5709 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5710 cfclose(Multi_chat_stream);
5714 case GS_STATE_DEBRIEF:
5715 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5720 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5721 multi_df_debrief_close();
5724 case GS_STATE_LOAD_MISSION_MENU:
5725 mission_load_menu_close();
5728 case GS_STATE_SIMULATOR_ROOM:
5732 case GS_STATE_CAMPAIGN_ROOM:
5733 campaign_room_close();
5736 case GS_STATE_CMD_BRIEF:
5737 if (new_state == GS_STATE_OPTIONS_MENU) {
5742 if (new_state == GS_STATE_MAIN_MENU)
5743 freespace_stop_mission();
5748 case GS_STATE_RED_ALERT:
5752 case GS_STATE_SHIP_SELECT:
5753 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5754 new_state != GS_STATE_HOTKEY_SCREEN &&
5755 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5756 common_select_close();
5757 if ( new_state == GS_STATE_MAIN_MENU ) {
5758 freespace_stop_mission();
5763 case GS_STATE_WEAPON_SELECT:
5764 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5765 new_state != GS_STATE_HOTKEY_SCREEN &&
5766 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5767 common_select_close();
5768 if ( new_state == GS_STATE_MAIN_MENU ) {
5769 freespace_stop_mission();
5774 case GS_STATE_TEAM_SELECT:
5775 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5776 new_state != GS_STATE_HOTKEY_SCREEN &&
5777 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5778 common_select_close();
5779 if ( new_state == GS_STATE_MAIN_MENU ) {
5780 freespace_stop_mission();
5785 case GS_STATE_MAIN_MENU:
5786 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5793 case GS_STATE_OPTIONS_MENU:
5794 //game_start_time();
5795 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5796 multi_join_clear_game_list();
5798 options_menu_close();
5801 case GS_STATE_BARRACKS_MENU:
5802 if(new_state != GS_STATE_VIEW_MEDALS){
5807 case GS_STATE_MISSION_LOG_SCROLLBACK:
5808 hud_scrollback_close();
5811 case GS_STATE_TRAINING_MENU:
5812 training_menu_close();
5815 case GS_STATE_GAME_PLAY:
5816 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5817 player_save_target_and_weapon_link_prefs();
5818 game_stop_looped_sounds();
5821 sound_env_disable();
5822 joy_ff_stop_effects();
5824 // stop game time under certain conditions
5825 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5830 // shut down any recording or playing demos
5835 // when in multiplayer and going back to the main menu, send a leave game packet
5836 // right away (before calling stop mission). stop_mission was taking to long to
5837 // close mission down and I want people to get notified ASAP.
5838 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5839 multi_quit_game(PROMPT_NONE);
5842 freespace_stop_mission();
5843 Game_time_compression = F1_0;
5847 case GS_STATE_TECH_MENU:
5851 case GS_STATE_TRAINING_PAUSED:
5852 Training_num_lines = 0;
5853 // fall through to GS_STATE_GAME_PAUSED
5855 case GS_STATE_GAME_PAUSED:
5857 if ( end_mission ) {
5862 case GS_STATE_DEBUG_PAUSED:
5865 pause_debug_close();
5869 case GS_STATE_HUD_CONFIG:
5873 // join/start a game
5874 case GS_STATE_MULTI_JOIN_GAME:
5875 if(new_state != GS_STATE_OPTIONS_MENU){
5876 multi_join_game_close();
5880 case GS_STATE_MULTI_HOST_SETUP:
5881 case GS_STATE_MULTI_CLIENT_SETUP:
5882 // if this is just the host going into the options screen, don't do anything
5883 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5887 // close down the proper state
5888 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5889 multi_create_game_close();
5891 multi_game_client_setup_close();
5894 // COMMAND LINE OPTION
5895 if (Cmdline_multi_stream_chat_to_file){
5896 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5897 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5898 cfclose(Multi_chat_stream);
5903 case GS_STATE_CONTROL_CONFIG:
5904 control_config_close();
5907 case GS_STATE_DEATH_DIED:
5908 Game_mode &= ~GM_DEAD_DIED;
5910 // early end while respawning or blowing up in a multiplayer game
5911 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5913 freespace_stop_mission();
5917 case GS_STATE_DEATH_BLEW_UP:
5918 Game_mode &= ~GM_DEAD_BLEW_UP;
5920 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5921 // to determine if I should do anything.
5922 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5924 freespace_stop_mission();
5927 // if we are not respawing as an observer or as a player, our new state will not
5928 // be gameplay state.
5929 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5930 game_stop_time(); // hasn't been called yet!!
5931 freespace_stop_mission();
5937 case GS_STATE_CREDITS:
5941 case GS_STATE_VIEW_MEDALS:
5945 case GS_STATE_SHOW_GOALS:
5946 mission_show_goals_close();
5949 case GS_STATE_HOTKEY_SCREEN:
5950 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5951 mission_hotkey_close();
5955 case GS_STATE_MULTI_MISSION_SYNC:
5956 // if we're moving into the options menu, don't do anything
5957 if(new_state == GS_STATE_OPTIONS_MENU){
5961 Assert( Game_mode & GM_MULTIPLAYER );
5963 if ( new_state == GS_STATE_GAME_PLAY ){
5964 // palette_restore_palette();
5966 // change a couple of flags to indicate our state!!!
5967 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5968 send_netplayer_update_packet();
5970 // set the game mode
5971 Game_mode |= GM_IN_MISSION;
5975 case GS_STATE_VIEW_CUTSCENES:
5976 cutscenes_screen_close();
5979 case GS_STATE_MULTI_STD_WAIT:
5980 multi_standalone_wait_close();
5983 case GS_STATE_STANDALONE_MAIN:
5984 standalone_main_close();
5985 if(new_state == GS_STATE_MULTI_STD_WAIT){
5986 init_multiplayer_stats();
5990 case GS_STATE_MULTI_PAUSED:
5991 // if ( end_mission ){
5996 case GS_STATE_INGAME_PRE_JOIN:
5997 multi_ingame_select_close();
6000 case GS_STATE_STANDALONE_POSTGAME:
6001 multi_standalone_postgame_close();
6004 case GS_STATE_INITIAL_PLAYER_SELECT:
6005 player_select_close();
6008 case GS_STATE_MULTI_START_GAME:
6009 multi_start_game_close();
6012 case GS_STATE_MULTI_HOST_OPTIONS:
6013 multi_host_options_close();
6016 case GS_STATE_END_OF_CAMPAIGN:
6017 mission_campaign_end_close();
6020 case GS_STATE_LOOP_BRIEF:
6026 // Called when a state is being entered.
6027 // The current state is set to the state we're entering at
6028 // this point, and old_state is set to the state we're coming
6029 // from. You should never try to change the state
6030 // in here... if you think you need to, you probably really
6031 // need to post an event, not change the state.
6033 void game_enter_state( int old_state, int new_state )
6035 switch (new_state) {
6036 case GS_STATE_MAIN_MENU:
6037 // in multiplayer mode, be sure that we are not doing networking anymore.
6038 if ( Game_mode & GM_MULTIPLAYER ) {
6039 Assert( Net_player != NULL );
6040 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
6043 Game_time_compression = F1_0;
6045 // determine which ship this guy is currently based on
6046 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6049 if (Player->on_bastion) {
6057 case GS_STATE_BRIEFING:
6058 main_hall_stop_music();
6059 main_hall_stop_ambient();
6061 if (Game_mode & GM_NORMAL) {
6062 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6063 // MWA: or from options or hotkey screens
6064 // JH: or if the command brief state already did this
6065 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6066 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
6067 && (old_state != GS_STATE_CMD_BRIEF) ) {
6068 if ( !game_start_mission() ) // this should put us into a new state on failure!
6072 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6073 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6074 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6076 Game_time_compression = F1_0;
6078 if ( red_alert_mission() ) {
6079 gameseq_post_event(GS_EVENT_RED_ALERT);
6086 case GS_STATE_DEBRIEF:
6087 game_stop_looped_sounds();
6088 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
6089 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
6094 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6095 multi_df_debrief_init();
6098 case GS_STATE_LOAD_MISSION_MENU:
6099 mission_load_menu_init();
6102 case GS_STATE_SIMULATOR_ROOM:
6106 case GS_STATE_CAMPAIGN_ROOM:
6107 campaign_room_init();
6110 case GS_STATE_RED_ALERT:
6111 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6115 case GS_STATE_CMD_BRIEF: {
6116 int team_num = 0; // team number used as index for which cmd brief to use.
6118 if (old_state == GS_STATE_OPTIONS_MENU) {
6122 main_hall_stop_music();
6123 main_hall_stop_ambient();
6125 if (Game_mode & GM_NORMAL) {
6126 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6127 // MWA: or from options or hotkey screens
6128 // JH: or if the command brief state already did this
6129 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6130 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
6131 if ( !game_start_mission() ) // this should put us into a new state on failure!
6136 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6137 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6138 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6140 cmd_brief_init(team_num);
6146 case GS_STATE_SHIP_SELECT:
6150 case GS_STATE_WEAPON_SELECT:
6151 weapon_select_init();
6154 case GS_STATE_TEAM_SELECT:
6158 case GS_STATE_GAME_PAUSED:
6163 case GS_STATE_DEBUG_PAUSED:
6164 // game_stop_time();
6165 // os_set_title("FreeSpace - PAUSED");
6168 case GS_STATE_TRAINING_PAUSED:
6175 case GS_STATE_OPTIONS_MENU:
6177 options_menu_init();
6180 case GS_STATE_GAME_PLAY:
6181 // coming from the gameplay state or the main menu, we might need to load the mission
6182 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
6183 if ( !game_start_mission() ) // this should put us into a new state.
6188 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
6189 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
6190 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
6191 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
6192 (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) ) {
6193 // JAS: Used to do all paging here.
6197 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
6201 main_hall_stop_music();
6202 main_hall_stop_ambient();
6203 event_music_first_pattern(); // start the first pattern
6206 // special code that restores player ship selection and weapons loadout when doing a quick start
6207 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
6208 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
6209 wss_direct_restore_loadout();
6213 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
6214 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
6215 event_music_first_pattern(); // start the first pattern
6218 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
6219 event_music_first_pattern(); // start the first pattern
6221 player_restore_target_and_weapon_link_prefs();
6223 Game_mode |= GM_IN_MISSION;
6226 // required to truely make mouse deltas zeroed in debug mouse code
6227 void mouse_force_pos(int x, int y);
6228 if (!Is_standalone) {
6229 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6235 // only start time if in single player, or coming from multi wait state
6238 (Game_mode & GM_NORMAL) &&
6239 (old_state != GS_STATE_VIEW_CUTSCENES)
6241 (Game_mode & GM_MULTIPLAYER) && (
6242 (old_state == GS_STATE_MULTI_PAUSED) ||
6243 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6249 // when coming from the multi paused state, reset the timestamps
6250 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6251 multi_reset_timestamps();
6254 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6255 // initialize all object update details
6256 multi_oo_gameplay_init();
6259 // under certain circumstances, the server should reset the object update rate limiting stuff
6260 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6261 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6263 // reinitialize the rate limiting system for all clients
6264 multi_oo_rate_init_all();
6267 // multiplayer clients should always re-initialize their control info rate limiting system
6268 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6269 multi_oo_rate_init_all();
6273 if(Game_mode & GM_MULTIPLAYER){
6274 multi_ping_reset_players();
6277 Game_subspace_effect = 0;
6278 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6279 Game_subspace_effect = 1;
6280 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6281 game_start_subspace_ambient_sound();
6285 sound_env_set(&Game_sound_env);
6286 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6288 // clear multiplayer button info i
6289 extern button_info Multi_ship_status_bi;
6290 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6293 case GS_STATE_HUD_CONFIG:
6297 case GS_STATE_MULTI_JOIN_GAME:
6298 multi_join_clear_game_list();
6300 if (old_state != GS_STATE_OPTIONS_MENU) {
6301 multi_join_game_init();
6306 case GS_STATE_MULTI_HOST_SETUP:
6307 // don't reinitialize if we're coming back from the host options screen
6308 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6309 multi_create_game_init();
6314 case GS_STATE_MULTI_CLIENT_SETUP:
6315 if (old_state != GS_STATE_OPTIONS_MENU) {
6316 multi_game_client_setup_init();
6321 case GS_STATE_CONTROL_CONFIG:
6322 control_config_init();
6325 case GS_STATE_TECH_MENU:
6329 case GS_STATE_BARRACKS_MENU:
6330 if(old_state != GS_STATE_VIEW_MEDALS){
6335 case GS_STATE_MISSION_LOG_SCROLLBACK:
6336 hud_scrollback_init();
6339 case GS_STATE_DEATH_DIED:
6340 Player_died_time = timestamp(10);
6342 if(!(Game_mode & GM_MULTIPLAYER)){
6343 player_show_death_message();
6345 Game_mode |= GM_DEAD_DIED;
6348 case GS_STATE_DEATH_BLEW_UP:
6349 if ( !popupdead_is_active() ) {
6350 Player_ai->target_objnum = -1;
6353 // stop any local EMP effect
6356 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6357 Game_mode |= GM_DEAD_BLEW_UP;
6358 Show_viewing_from_self = 0;
6360 // timestamp how long we should wait before displaying the died popup
6361 if ( !popupdead_is_active() ) {
6362 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6366 case GS_STATE_GAMEPLAY_HELP:
6367 gameplay_help_init();
6370 case GS_STATE_CREDITS:
6371 main_hall_stop_music();
6372 main_hall_stop_ambient();
6376 case GS_STATE_VIEW_MEDALS:
6377 medal_main_init(Player);
6380 case GS_STATE_SHOW_GOALS:
6381 mission_show_goals_init();
6384 case GS_STATE_HOTKEY_SCREEN:
6385 mission_hotkey_init();
6388 case GS_STATE_MULTI_MISSION_SYNC:
6389 // if we're coming from the options screen, don't do any
6390 if(old_state == GS_STATE_OPTIONS_MENU){
6394 switch(Multi_sync_mode){
6395 case MULTI_SYNC_PRE_BRIEFING:
6396 // if moving from game forming to the team select state
6399 case MULTI_SYNC_POST_BRIEFING:
6400 // if moving from briefing into the mission itself
6403 // tell everyone that we're now loading data
6404 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6405 send_netplayer_update_packet();
6407 // JAS: Used to do all paging here!!!!
6409 Net_player->state = NETPLAYER_STATE_WAITING;
6410 send_netplayer_update_packet();
6412 Game_time_compression = F1_0;
6414 case MULTI_SYNC_INGAME:
6420 case GS_STATE_VIEW_CUTSCENES:
6421 cutscenes_screen_init();
6424 case GS_STATE_MULTI_STD_WAIT:
6425 multi_standalone_wait_init();
6428 case GS_STATE_STANDALONE_MAIN:
6429 // don't initialize if we're coming from one of these 2 states unless there are no
6430 // players left (reset situation)
6431 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6432 standalone_main_init();
6436 case GS_STATE_MULTI_PAUSED:
6440 case GS_STATE_INGAME_PRE_JOIN:
6441 multi_ingame_select_init();
6444 case GS_STATE_STANDALONE_POSTGAME:
6445 multi_standalone_postgame_init();
6448 case GS_STATE_INITIAL_PLAYER_SELECT:
6449 player_select_init();
6452 case GS_STATE_MULTI_START_GAME:
6453 multi_start_game_init();
6456 case GS_STATE_MULTI_HOST_OPTIONS:
6457 multi_host_options_init();
6460 case GS_STATE_END_OF_CAMPAIGN:
6461 mission_campaign_end_init();
6464 case GS_STATE_LOOP_BRIEF:
6471 // do stuff that may need to be done regardless of state
6472 void game_do_state_common(int state,int no_networking)
6474 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6475 snd_do_frame(); // update sound system
6476 event_music_do_frame(); // music needs to play across many states
6478 multi_log_process();
6480 if (no_networking) {
6484 // maybe do a multiplayer frame based on game mode and state type
6485 if (Game_mode & GM_MULTIPLAYER) {
6487 case GS_STATE_OPTIONS_MENU:
6488 case GS_STATE_GAMEPLAY_HELP:
6489 case GS_STATE_HOTKEY_SCREEN:
6490 case GS_STATE_HUD_CONFIG:
6491 case GS_STATE_CONTROL_CONFIG:
6492 case GS_STATE_MISSION_LOG_SCROLLBACK:
6493 case GS_STATE_SHOW_GOALS:
6494 case GS_STATE_VIEW_CUTSCENES:
6495 case GS_STATE_EVENT_DEBUG:
6496 multi_maybe_do_frame();
6500 game_do_networking();
6504 // Called once a frame.
6505 // You should never try to change the state
6506 // in here... if you think you need to, you probably really
6507 // need to post an event, not change the state.
6508 int Game_do_state_should_skip = 0;
6509 void game_do_state(int state)
6511 // always lets the do_state_common() function determine if the state should be skipped
6512 Game_do_state_should_skip = 0;
6514 // legal to set the should skip state anywhere in this function
6515 game_do_state_common(state); // do stuff that may need to be done regardless of state
6517 if(Game_do_state_should_skip){
6522 case GS_STATE_MAIN_MENU:
6523 game_set_frametime(GS_STATE_MAIN_MENU);
6524 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6527 main_hall_do(flFrametime);
6531 case GS_STATE_OPTIONS_MENU:
6532 game_set_frametime(GS_STATE_OPTIONS_MENU);
6533 options_menu_do_frame(flFrametime);
6536 case GS_STATE_BARRACKS_MENU:
6537 game_set_frametime(GS_STATE_BARRACKS_MENU);
6538 barracks_do_frame(flFrametime);
6541 case GS_STATE_TRAINING_MENU:
6542 game_set_frametime(GS_STATE_TRAINING_MENU);
6543 training_menu_do_frame(flFrametime);
6546 case GS_STATE_TECH_MENU:
6547 game_set_frametime(GS_STATE_TECH_MENU);
6548 techroom_do_frame(flFrametime);
6551 case GS_STATE_GAMEPLAY_HELP:
6552 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6553 gameplay_help_do_frame(flFrametime);
6556 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6560 case GS_STATE_GAME_PAUSED:
6564 case GS_STATE_DEBUG_PAUSED:
6566 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6571 case GS_STATE_TRAINING_PAUSED:
6572 game_training_pause_do();
6575 case GS_STATE_LOAD_MISSION_MENU:
6576 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6577 mission_load_menu_do();
6580 case GS_STATE_BRIEFING:
6581 game_set_frametime(GS_STATE_BRIEFING);
6582 brief_do_frame(flFrametime);
6585 case GS_STATE_DEBRIEF:
6586 game_set_frametime(GS_STATE_DEBRIEF);
6587 debrief_do_frame(flFrametime);
6590 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6591 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6592 multi_df_debrief_do();
6595 case GS_STATE_SHIP_SELECT:
6596 game_set_frametime(GS_STATE_SHIP_SELECT);
6597 ship_select_do(flFrametime);
6600 case GS_STATE_WEAPON_SELECT:
6601 game_set_frametime(GS_STATE_WEAPON_SELECT);
6602 weapon_select_do(flFrametime);
6605 case GS_STATE_MISSION_LOG_SCROLLBACK:
6606 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6607 hud_scrollback_do_frame(flFrametime);
6610 case GS_STATE_HUD_CONFIG:
6611 game_set_frametime(GS_STATE_HUD_CONFIG);
6612 hud_config_do_frame(flFrametime);
6615 case GS_STATE_MULTI_JOIN_GAME:
6616 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6617 multi_join_game_do_frame();
6620 case GS_STATE_MULTI_HOST_SETUP:
6621 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6622 multi_create_game_do();
6625 case GS_STATE_MULTI_CLIENT_SETUP:
6626 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6627 multi_game_client_setup_do_frame();
6630 case GS_STATE_CONTROL_CONFIG:
6631 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6632 control_config_do_frame(flFrametime);
6635 case GS_STATE_DEATH_DIED:
6639 case GS_STATE_DEATH_BLEW_UP:
6643 case GS_STATE_SIMULATOR_ROOM:
6644 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6645 sim_room_do_frame(flFrametime);
6648 case GS_STATE_CAMPAIGN_ROOM:
6649 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6650 campaign_room_do_frame(flFrametime);
6653 case GS_STATE_RED_ALERT:
6654 game_set_frametime(GS_STATE_RED_ALERT);
6655 red_alert_do_frame(flFrametime);
6658 case GS_STATE_CMD_BRIEF:
6659 game_set_frametime(GS_STATE_CMD_BRIEF);
6660 cmd_brief_do_frame(flFrametime);
6663 case GS_STATE_CREDITS:
6664 game_set_frametime(GS_STATE_CREDITS);
6665 credits_do_frame(flFrametime);
6668 case GS_STATE_VIEW_MEDALS:
6669 game_set_frametime(GS_STATE_VIEW_MEDALS);
6673 case GS_STATE_SHOW_GOALS:
6674 game_set_frametime(GS_STATE_SHOW_GOALS);
6675 mission_show_goals_do_frame(flFrametime);
6678 case GS_STATE_HOTKEY_SCREEN:
6679 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6680 mission_hotkey_do_frame(flFrametime);
6683 case GS_STATE_VIEW_CUTSCENES:
6684 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6685 cutscenes_screen_do_frame();
6688 case GS_STATE_MULTI_STD_WAIT:
6689 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6690 multi_standalone_wait_do();
6693 case GS_STATE_STANDALONE_MAIN:
6694 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6695 standalone_main_do();
6698 case GS_STATE_MULTI_PAUSED:
6699 game_set_frametime(GS_STATE_MULTI_PAUSED);
6703 case GS_STATE_TEAM_SELECT:
6704 game_set_frametime(GS_STATE_TEAM_SELECT);
6708 case GS_STATE_INGAME_PRE_JOIN:
6709 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6710 multi_ingame_select_do();
6713 case GS_STATE_EVENT_DEBUG:
6715 game_set_frametime(GS_STATE_EVENT_DEBUG);
6716 game_show_event_debug(flFrametime);
6720 case GS_STATE_STANDALONE_POSTGAME:
6721 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6722 multi_standalone_postgame_do();
6725 case GS_STATE_INITIAL_PLAYER_SELECT:
6726 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6730 case GS_STATE_MULTI_MISSION_SYNC:
6731 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6735 case GS_STATE_MULTI_START_GAME:
6736 game_set_frametime(GS_STATE_MULTI_START_GAME);
6737 multi_start_game_do();
6740 case GS_STATE_MULTI_HOST_OPTIONS:
6741 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6742 multi_host_options_do();
6745 case GS_STATE_END_OF_CAMPAIGN:
6746 mission_campaign_end_do();
6749 case GS_STATE_END_DEMO:
6750 game_set_frametime(GS_STATE_END_DEMO);
6751 end_demo_campaign_do();
6754 case GS_STATE_LOOP_BRIEF:
6755 game_set_frametime(GS_STATE_LOOP_BRIEF);
6759 } // end switch(gs_current_state)
6763 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6764 int game_do_ram_check(int ram_in_bytes)
6766 if ( ram_in_bytes < 30*1024*1024 ) {
6767 int allowed_to_run = 1;
6768 if ( ram_in_bytes < 25*1024*1024 ) {
6773 int Freespace_total_ram_MB;
6774 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6776 if ( allowed_to_run ) {
6778 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);
6783 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6784 if ( msgbox_rval == IDCANCEL ) {
6791 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);
6793 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6804 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6805 // If so, copy it over and remove the update directory.
6806 void game_maybe_update_launcher(char *exe_dir)
6809 char src_filename[MAX_PATH];
6810 char dest_filename[MAX_PATH];
6812 strcpy(src_filename, exe_dir);
6813 strcat(src_filename, NOX("\\update\\freespace.exe"));
6815 strcpy(dest_filename, exe_dir);
6816 strcat(dest_filename, NOX("\\freespace.exe"));
6818 // see if src_filename exists
6820 fp = fopen(src_filename, "rb");
6826 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6828 // copy updated freespace.exe to freespace exe dir
6829 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6830 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 );
6834 // delete the file in the update directory
6835 DeleteFile(src_filename);
6837 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6838 char update_dir[MAX_PATH];
6839 strcpy(update_dir, exe_dir);
6840 strcat(update_dir, NOX("\\update"));
6841 RemoveDirectory(update_dir);
6847 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6851 int sub_total_destroyed = 0;
6855 // get the total for all his children
6856 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6857 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6860 // find the # of faces for this _individual_ object
6861 total = submodel_get_num_polys(model_num, sm);
6862 if(strstr(pm->submodel[sm].name, "-destroyed")){
6863 sub_total_destroyed = total;
6867 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6870 *out_total += total + sub_total;
6871 *out_destroyed_total += sub_total_destroyed;
6874 #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);
6875 void game_spew_pof_info()
6877 char *pof_list[1000];
6880 int idx, model_num, i, j;
6882 int total, root_total, model_total, destroyed_total, counted;
6886 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6888 // spew info on all the pofs
6894 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6899 for(idx=0; idx<num_files; idx++, counted++){
6900 sprintf(str, "%s.pof", pof_list[idx]);
6901 model_num = model_load(str, 0, NULL);
6903 pm = model_get(model_num);
6905 // if we have a real model
6910 // go through and print all raw submodels
6911 cfputs("RAW\n", out);
6914 for (i=0; i<pm->n_models; i++) {
6915 total = submodel_get_num_polys(model_num, i);
6917 model_total += total;
6918 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6921 sprintf(str, "Model total %d\n", model_total);
6924 // now go through and do it by LOD
6925 cfputs("BY LOD\n\n", out);
6926 for(i=0; i<pm->n_detail_levels; i++){
6927 sprintf(str, "LOD %d\n", i);
6931 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6933 destroyed_total = 0;
6934 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6935 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6938 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6941 sprintf(str, "TOTAL: %d\n", total + root_total);
6943 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6945 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6948 cfputs("------------------------------------------------------------------------\n\n", out);
6952 if(counted >= MAX_POLYGON_MODELS - 5){
6965 game_spew_pof_info();
6968 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6973 // Don't let more than one instance of Freespace run.
6974 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6976 SetForegroundWindow(hwnd);
6981 // Find out how much RAM is on this machine
6984 ms.dwLength = sizeof(MEMORYSTATUS);
6985 GlobalMemoryStatus(&ms);
6986 Freespace_total_ram = ms.dwTotalPhys;
6988 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6992 if ( ms.dwTotalVirtual < 1024 ) {
6993 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6997 if (!vm_init(24*1024*1024)) {
6998 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 );
7002 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
7004 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);
7012 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
7013 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
7014 seem worth bothering with.
7018 lResult = RegOpenKeyEx(
7019 HKEY_LOCAL_MACHINE, // Where it is
7020 "Software\\Microsoft\\DirectX", // name of key
7021 NULL, // DWORD reserved
7022 KEY_QUERY_VALUE, // Allows all changes
7023 &hKey // Location to store key
7026 if (lResult == ERROR_SUCCESS) {
7028 DWORD dwType, dwLen;
7031 lResult = RegQueryValueEx(
7032 hKey, // Handle to key
7033 "Version", // The values name
7034 NULL, // DWORD reserved
7035 &dwType, // What kind it is
7036 (ubyte *) version, // value to set
7037 &dwLen // How many bytes to set
7040 if (lResult == ERROR_SUCCESS) {
7041 dx_version = atoi(strstr(version, ".") + 1);
7045 DWORD dwType, dwLen;
7048 lResult = RegQueryValueEx(
7049 hKey, // Handle to key
7050 "InstalledVersion", // The values name
7051 NULL, // DWORD reserved
7052 &dwType, // What kind it is
7053 (ubyte *) &val, // value to set
7054 &dwLen // How many bytes to set
7057 if (lResult == ERROR_SUCCESS) {
7065 if (dx_version < 3) {
7066 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
7067 "latest version of DirectX at:\n\n"
7068 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
7070 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
7071 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
7076 //=====================================================
7077 // Make sure we're running in the right directory.
7081 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
7082 char *p = exe_dir + strlen(exe_dir);
7084 // chop off the filename
7085 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
7091 if ( strlen(exe_dir) > 0 ) {
7092 SetCurrentDirectory(exe_dir);
7095 // check for updated freespace.exe
7096 game_maybe_update_launcher(exe_dir);
7104 extern void windebug_memwatch_init();
7105 windebug_memwatch_init();
7109 parse_cmdline(szCmdLine);
7111 #ifdef STANDALONE_ONLY_BUILD
7113 nprintf(("Network", "Standalone running"));
7116 nprintf(("Network", "Standalone running"));
7124 // maybe spew pof stuff
7125 if(Cmdline_spew_pof_info){
7126 game_spew_pof_info();
7131 // non-demo, non-standalone, play the intro movie
7136 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) ){
7138 #if defined(OEM_BUILD)
7139 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
7141 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
7142 #endif // defined(OEM_BUILD)
7147 if ( !Is_standalone ) {
7149 // release -- movies always play
7152 // 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
7153 movie_play( NOX("intro.mve"), 0 );
7155 // debug version, movie will only play with -showmovies
7156 #elif !defined(NDEBUG)
7158 movie_play( NOX("intro.mve"), 0);
7161 if ( Cmdline_show_movies )
7162 movie_play( NOX("intro.mve"), 0 );
7171 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
7173 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
7177 // only important for non THREADED mode
7180 state = gameseq_process_events();
7181 if ( state == GS_STATE_QUIT_GAME ){
7186 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7188 demo_upsell_show_screens();
7190 #elif defined(OEM_BUILD)
7191 // show upsell screens on exit
7192 oem_upsell_show_screens();
7199 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7205 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7207 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
7209 // Do nothing here - RecordExceptionInfo() has already done
7210 // everything that is needed. Actually this code won't even
7211 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
7212 // the __except clause.
7216 nprintf(("WinMain", "exceptions shall fall through"));
7218 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7224 // launcher the fslauncher program on exit
7225 void game_launch_launcher_on_exit()
7229 PROCESS_INFORMATION pi;
7230 char cmd_line[2048];
7231 char original_path[1024] = "";
7233 memset( &si, 0, sizeof(STARTUPINFO) );
7237 _getcwd(original_path, 1023);
7239 // set up command line
7240 strcpy(cmd_line, original_path);
7241 strcat(cmd_line, "\\");
7242 strcat(cmd_line, LAUNCHER_FNAME);
7243 strcat(cmd_line, " -straight_to_update");
7245 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7246 cmd_line, // pointer to command line string
7247 NULL, // pointer to process security attributes
7248 NULL, // pointer to thread security attributes
7249 FALSE, // handle inheritance flag
7250 CREATE_DEFAULT_ERROR_MODE, // creation flags
7251 NULL, // pointer to new environment block
7252 NULL, // pointer to current directory name
7253 &si, // pointer to STARTUPINFO
7254 &pi // pointer to PROCESS_INFORMATION
7256 // to eliminate build warnings
7266 // This function is called when FreeSpace terminates normally.
7268 void game_shutdown(void)
7274 // don't ever flip a page on the standalone!
7275 if(!(Game_mode & GM_STANDALONE_SERVER)){
7281 // if the player has left the "player select" screen and quit the game without actually choosing
7282 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7283 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7287 // load up common multiplayer icons
7288 multi_unload_common_icons();
7290 shockwave_close(); // release any memory used by shockwave system
7291 fireball_close(); // free fireball system
7292 ship_close(); // free any memory that was allocated for the ships
7293 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7294 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7295 bm_unload_all(); // free bitmaps
7296 mission_campaign_close(); // close out the campaign stuff
7297 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7299 #ifdef MULTI_USE_LAG
7303 // the menu close functions will unload the bitmaps if they were displayed during the game
7304 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7307 training_menu_close();
7310 extern void joy_close();
7313 audiostream_close();
7315 event_music_close();
7319 // HACKITY HACK HACK
7320 // if this flag is set, we should be firing up the launcher when exiting freespace
7321 extern int Multi_update_fireup_launcher_on_exit;
7322 if(Multi_update_fireup_launcher_on_exit){
7323 game_launch_launcher_on_exit();
7327 // game_stop_looped_sounds()
7329 // This function will call the appropriate stop looped sound functions for those
7330 // modules which use looping sounds. It is not enough just to stop a looping sound
7331 // at the DirectSound level, the game is keeping track of looping sounds, and this
7332 // function is used to inform the game that looping sounds are being halted.
7334 void game_stop_looped_sounds()
7336 hud_stop_looped_locking_sounds();
7337 hud_stop_looped_engine_sounds();
7338 afterburner_stop_sounds();
7339 player_stop_looped_sounds();
7340 obj_snd_stop_all(); // stop all object-linked persistant sounds
7341 game_stop_subspace_ambient_sound();
7342 snd_stop(Radar_static_looping);
7343 Radar_static_looping = -1;
7344 snd_stop(Target_static_looping);
7345 shipfx_stop_engine_wash_sound();
7346 Target_static_looping = -1;
7349 //////////////////////////////////////////////////////////////////////////
7351 // Code for supporting an animating mouse pointer
7354 //////////////////////////////////////////////////////////////////////////
7356 typedef struct animating_obj
7365 static animating_obj Animating_mouse;
7367 // ----------------------------------------------------------------------------
7368 // init_animating_pointer()
7370 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7371 // gets properly initialized
7373 void init_animating_pointer()
7375 Animating_mouse.first_frame = -1;
7376 Animating_mouse.num_frames = 0;
7377 Animating_mouse.current_frame = -1;
7378 Animating_mouse.time = 0.0f;
7379 Animating_mouse.elapsed_time = 0.0f;
7382 // ----------------------------------------------------------------------------
7383 // load_animating_pointer()
7385 // Called at game init to load in the frames for the animating mouse pointer
7387 // input: filename => filename of animation file that holds the animation
7389 void load_animating_pointer(char *filename, int dx, int dy)
7394 init_animating_pointer();
7396 am = &Animating_mouse;
7397 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7398 if ( am->first_frame == -1 )
7399 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7400 am->current_frame = 0;
7401 am->time = am->num_frames / i2fl(fps);
7404 // ----------------------------------------------------------------------------
7405 // unload_animating_pointer()
7407 // Called at game shutdown to free the memory used to store the animation frames
7409 void unload_animating_pointer()
7414 am = &Animating_mouse;
7415 for ( i = 0; i < am->num_frames; i++ ) {
7416 Assert( (am->first_frame+i) >= 0 );
7417 bm_release(am->first_frame + i);
7420 am->first_frame = -1;
7422 am->current_frame = -1;
7425 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7426 void game_render_mouse(float frametime)
7431 // if animating cursor exists, play the next frame
7432 am = &Animating_mouse;
7433 if ( am->first_frame != -1 ) {
7434 mouse_get_pos(&mx, &my);
7435 am->elapsed_time += frametime;
7436 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7437 if ( am->current_frame >= am->num_frames ) {
7438 am->current_frame = 0;
7439 am->elapsed_time = 0.0f;
7441 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7445 // ----------------------------------------------------------------------------
7446 // game_maybe_draw_mouse()
7448 // determines whether to draw the mouse pointer at all, and what frame of
7449 // animation to use if the mouse is animating
7451 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7453 // input: frametime => elapsed frame time in seconds since last call
7455 void game_maybe_draw_mouse(float frametime)
7459 game_state = gameseq_get_state();
7461 switch ( game_state ) {
7462 case GS_STATE_GAME_PAUSED:
7463 // case GS_STATE_MULTI_PAUSED:
7464 case GS_STATE_GAME_PLAY:
7465 case GS_STATE_DEATH_DIED:
7466 case GS_STATE_DEATH_BLEW_UP:
7467 if ( popup_active() || popupdead_is_active() ) {
7479 if ( !Mouse_hidden )
7480 game_render_mouse(frametime);
7484 void game_do_training_checks()
7488 waypoint_list *wplp;
7490 if (Training_context & TRAINING_CONTEXT_SPEED) {
7491 s = (int) Player_obj->phys_info.fspeed;
7492 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7493 if (!Training_context_speed_set) {
7494 Training_context_speed_set = 1;
7495 Training_context_speed_timestamp = timestamp();
7499 Training_context_speed_set = 0;
7502 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7503 wplp = &Waypoint_lists[Training_context_path];
7504 if (wplp->count > Training_context_goal_waypoint) {
7505 i = Training_context_goal_waypoint;
7507 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7508 if (d <= Training_context_distance) {
7509 Training_context_at_waypoint = i;
7510 if (Training_context_goal_waypoint == i) {
7511 Training_context_goal_waypoint++;
7512 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7519 if (i == wplp->count)
7522 } while (i != Training_context_goal_waypoint);
7526 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7527 Players_target = Player_ai->target_objnum;
7528 Players_targeted_subsys = Player_ai->targeted_subsys;
7529 Players_target_timestamp = timestamp();
7533 /////////// Following is for event debug view screen
7537 #define EVENT_DEBUG_MAX 5000
7538 #define EVENT_DEBUG_EVENT 0x8000
7540 int Event_debug_index[EVENT_DEBUG_MAX];
7543 void game_add_event_debug_index(int n, int indent)
7545 if (ED_count < EVENT_DEBUG_MAX)
7546 Event_debug_index[ED_count++] = n | (indent << 16);
7549 void game_add_event_debug_sexp(int n, int indent)
7554 if (Sexp_nodes[n].first >= 0) {
7555 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7556 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7560 game_add_event_debug_index(n, indent);
7561 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7562 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7564 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7567 void game_event_debug_init()
7572 for (e=0; e<Num_mission_events; e++) {
7573 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7574 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7578 void game_show_event_debug(float frametime)
7582 int font_height, font_width;
7584 static int scroll_offset = 0;
7586 k = game_check_key();
7592 if (scroll_offset < 0)
7602 scroll_offset -= 20;
7603 if (scroll_offset < 0)
7608 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7612 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7618 gr_set_color_fast(&Color_bright);
7620 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7622 gr_set_color_fast(&Color_normal);
7624 gr_get_string_size(&font_width, &font_height, NOX("test"));
7625 y_max = gr_screen.max_h - font_height - 5;
7629 while (k < ED_count) {
7630 if (y_index > y_max)
7633 z = Event_debug_index[k];
7634 if (z & EVENT_DEBUG_EVENT) {
7636 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7637 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7638 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7639 Mission_events[z].repeat_count, Mission_events[z].interval);
7647 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7648 switch (Sexp_nodes[z & 0x7fff].value) {
7650 strcat(buf, NOX(" (True)"));
7654 strcat(buf, NOX(" (False)"));
7657 case SEXP_KNOWN_TRUE:
7658 strcat(buf, NOX(" (Always true)"));
7661 case SEXP_KNOWN_FALSE:
7662 strcat(buf, NOX(" (Always false)"));
7665 case SEXP_CANT_EVAL:
7666 strcat(buf, NOX(" (Can't eval)"));
7670 case SEXP_NAN_FOREVER:
7671 strcat(buf, NOX(" (Not a number)"));
7676 gr_printf(10, y_index, buf);
7677 y_index += font_height;
7690 extern int Tmap_npixels;
7692 int Tmap_num_too_big = 0;
7693 int Num_models_needing_splitting = 0;
7695 void Time_model( int modelnum )
7697 // mprintf(( "Timing ship '%s'\n", si->name ));
7699 vector eye_pos, model_pos;
7700 matrix eye_orient, model_orient;
7702 polymodel *pm = model_get( modelnum );
7704 int l = strlen(pm->filename);
7706 if ( (l == '/') || (l=='\\') || (l==':')) {
7712 char *pof_file = &pm->filename[l];
7714 int model_needs_splitting = 0;
7716 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7718 for (i=0; i<pm->n_textures; i++ ) {
7719 char filename[1024];
7722 int bmp_num = pm->original_textures[i];
7723 if ( bmp_num > -1 ) {
7724 bm_get_palette(pm->original_textures[i], pal, filename );
7726 bm_get_info( pm->original_textures[i],&w, &h );
7729 if ( (w > 512) || (h > 512) ) {
7730 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7732 model_needs_splitting++;
7735 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7739 if ( model_needs_splitting ) {
7740 Num_models_needing_splitting++;
7742 eye_orient = model_orient = vmd_identity_matrix;
7743 eye_pos = model_pos = vmd_zero_vector;
7745 eye_pos.xyz.z = -pm->rad*2.0f;
7747 vector eye_to_model;
7749 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7750 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7752 fix t1 = timer_get_fixed_seconds();
7755 ta.p = ta.b = ta.h = 0.0f;
7760 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7762 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7764 modelstats_num_polys = modelstats_num_verts = 0;
7766 while( ta.h < PI2 ) {
7769 vm_angles_2_matrix(&m1, &ta );
7770 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7777 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7779 model_clear_instance( modelnum );
7780 model_set_detail_level(0); // use highest detail level
7781 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7789 int k = key_inkey();
7790 if ( k == KEY_ESC ) {
7795 fix t2 = timer_get_fixed_seconds();
7797 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7798 //bitmaps_used_this_frame /= framecount;
7800 modelstats_num_polys /= framecount;
7801 modelstats_num_verts /= framecount;
7803 Tmap_npixels /=framecount;
7806 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7807 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 );
7808 // 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 );
7814 int Time_models = 0;
7815 DCF_BOOL( time_models, Time_models );
7817 void Do_model_timings_test()
7821 if ( !Time_models ) return;
7823 mprintf(( "Timing models!\n" ));
7827 ubyte model_used[MAX_POLYGON_MODELS];
7828 int model_id[MAX_POLYGON_MODELS];
7829 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7834 for (i=0; i<Num_ship_types; i++ ) {
7835 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7837 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7838 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7841 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7842 if ( !Texture_fp ) return;
7844 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7845 if ( !Time_fp ) return;
7847 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7848 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7850 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7851 if ( model_used[i] ) {
7852 Time_model( model_id[i] );
7856 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7857 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7866 // Call this function when you want to inform the player that a feature is not
7867 // enabled in the DEMO version of FreSpace
7868 void game_feature_not_in_demo_popup()
7870 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7873 // format the specified time (fixed point) into a nice string
7874 void game_format_time(fix m_time,char *time_str)
7877 int hours,minutes,seconds;
7880 mtime = f2fl(m_time);
7882 // get the hours, minutes and seconds
7883 hours = (int)(mtime / 3600.0f);
7885 mtime -= (3600.0f * (float)hours);
7887 seconds = (int)mtime%60;
7888 minutes = (int)mtime/60;
7890 // print the hour if necessary
7892 sprintf(time_str,XSTR( "%d:", 201),hours);
7893 // if there are less than 10 minutes, print a leading 0
7895 strcpy(tmp,NOX("0"));
7896 strcat(time_str,tmp);
7900 // print the minutes
7902 sprintf(tmp,XSTR( "%d:", 201),minutes);
7903 strcat(time_str,tmp);
7905 sprintf(time_str,XSTR( "%d:", 201),minutes);
7908 // print the seconds
7910 strcpy(tmp,NOX("0"));
7911 strcat(time_str,tmp);
7913 sprintf(tmp,"%d",seconds);
7914 strcat(time_str,tmp);
7917 // Stuff version string in *str.
7918 void get_version_string(char *str)
7921 if ( FS_VERSION_BUILD == 0 ) {
7922 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7924 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7927 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7929 #elif defined (OEM_BUILD)
7930 strcat(str, " (OEM)");
7936 char myname[_MAX_PATH];
7937 int namelen, major, minor, build, waste;
7938 unsigned int buf_size;
7944 // Find my EXE file name
7945 hMod = GetModuleHandle(NULL);
7946 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7948 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7949 infop = (char *)malloc(version_size);
7950 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7952 // get the product version
7953 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7954 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7956 sprintf(str,"Dv%d.%02d",major, minor);
7958 sprintf(str,"v%d.%02d",major, minor);
7963 void get_version_string_short(char *str)
7965 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7968 // ----------------------------------------------------------------
7970 // OEM UPSELL SCREENS BEGIN
7972 // ----------------------------------------------------------------
7973 #if defined(OEM_BUILD)
7975 #define NUM_OEM_UPSELL_SCREENS 3
7976 #define OEM_UPSELL_SCREEN_DELAY 10000
7978 static int Oem_upsell_bitmaps_loaded = 0;
7979 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7980 static int Oem_upsell_screen_number = 0;
7981 static int Oem_upsell_show_next_bitmap_time;
7984 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7997 static int Oem_normal_cursor = -1;
7998 static int Oem_web_cursor = -1;
7999 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
8000 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
8002 void oem_upsell_next_screen()
8004 Oem_upsell_screen_number++;
8005 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
8006 // extra long delay, mouse shown on last upsell
8007 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
8011 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8015 void oem_upsell_load_bitmaps()
8019 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8020 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
8024 void oem_upsell_unload_bitmaps()
8028 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8029 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
8030 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
8035 Oem_upsell_bitmaps_loaded = 0;
8038 // clickable hotspot on 3rd OEM upsell screen
8039 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
8041 28, 350, 287, 96 // x, y, w, h
8044 45, 561, 460, 152 // x, y, w, h
8048 void oem_upsell_show_screens()
8050 int current_time, k;
8053 if ( !Oem_upsell_bitmaps_loaded ) {
8054 oem_upsell_load_bitmaps();
8055 Oem_upsell_bitmaps_loaded = 1;
8058 // may use upsell screens more than once
8059 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8060 Oem_upsell_screen_number = 0;
8066 int nframes; // used to pass, not really needed (should be 1)
8067 Oem_normal_cursor = gr_get_cursor_bitmap();
8068 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
8069 Assert(Oem_web_cursor >= 0);
8070 if (Oem_web_cursor < 0) {
8071 Oem_web_cursor = Oem_normal_cursor;
8076 //oem_reset_trailer_timer();
8078 current_time = timer_get_milliseconds();
8083 // advance screen on keypress or timeout
8084 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
8085 oem_upsell_next_screen();
8088 // check if we are done
8089 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
8090 Oem_upsell_screen_number--;
8093 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
8098 // show me the upsell
8099 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
8100 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
8104 // if this is the 3rd upsell, make it clickable, d00d
8105 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
8107 int button_state = mouse_get_pos(&mx, &my);
8108 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])
8109 && (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]) )
8112 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
8115 if (button_state & MOUSE_LEFT_BUTTON) {
8117 multi_pxo_url(OEM_UPSELL_URL);
8121 // switch cursor back to normal one
8122 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8127 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8137 oem_upsell_unload_bitmaps();
8139 // switch cursor back to normal one
8140 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8144 #endif // defined(OEM_BUILD)
8145 // ----------------------------------------------------------------
8147 // OEM UPSELL SCREENS END
8149 // ----------------------------------------------------------------
8153 // ----------------------------------------------------------------
8155 // DEMO UPSELL SCREENS BEGIN
8157 // ----------------------------------------------------------------
8159 #if defined(FS2_DEMO) || defined(FS1_DEMO)
8162 #define NUM_DEMO_UPSELL_SCREENS 2
8164 #define NUM_DEMO_UPSELL_SCREENS 4
8166 #define DEMO_UPSELL_SCREEN_DELAY 3000
8168 static int Demo_upsell_bitmaps_loaded = 0;
8169 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
8170 static int Demo_upsell_screen_number = 0;
8171 static int Demo_upsell_show_next_bitmap_time;
8174 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
8200 void demo_upsell_next_screen()
8202 Demo_upsell_screen_number++;
8203 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
8204 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
8206 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8210 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
8211 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8212 #ifndef HARDWARE_ONLY
8213 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8220 void demo_upsell_load_bitmaps()
8224 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8225 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
8229 void demo_upsell_unload_bitmaps()
8233 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8234 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8235 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8240 Demo_upsell_bitmaps_loaded = 0;
8243 void demo_upsell_show_screens()
8245 int current_time, k;
8248 if ( !Demo_upsell_bitmaps_loaded ) {
8249 demo_upsell_load_bitmaps();
8250 Demo_upsell_bitmaps_loaded = 1;
8253 // may use upsell screens more than once
8254 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8255 Demo_upsell_screen_number = 0;
8262 demo_reset_trailer_timer();
8264 current_time = timer_get_milliseconds();
8271 // don't time out, wait for keypress
8273 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8274 demo_upsell_next_screen();
8279 demo_upsell_next_screen();
8282 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8283 Demo_upsell_screen_number--;
8286 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8291 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8292 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8297 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8307 demo_upsell_unload_bitmaps();
8312 // ----------------------------------------------------------------
8314 // DEMO UPSELL SCREENS END
8316 // ----------------------------------------------------------------
8319 // ----------------------------------------------------------------
8321 // Subspace Ambient Sound START
8323 // ----------------------------------------------------------------
8325 static int Subspace_ambient_left_channel = -1;
8326 static int Subspace_ambient_right_channel = -1;
8329 void game_start_subspace_ambient_sound()
8331 if ( Subspace_ambient_left_channel < 0 ) {
8332 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8335 if ( Subspace_ambient_right_channel < 0 ) {
8336 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8340 void game_stop_subspace_ambient_sound()
8342 if ( Subspace_ambient_left_channel >= 0 ) {
8343 snd_stop(Subspace_ambient_left_channel);
8344 Subspace_ambient_left_channel = -1;
8347 if ( Subspace_ambient_right_channel >= 0 ) {
8348 snd_stop(Subspace_ambient_right_channel);
8349 Subspace_ambient_right_channel = -1;
8353 // ----------------------------------------------------------------
8355 // Subspace Ambient Sound END
8357 // ----------------------------------------------------------------
8359 // ----------------------------------------------------------------
8361 // CDROM detection code START
8363 // ----------------------------------------------------------------
8365 #define CD_SIZE_72_MINUTE_MAX (697000000)
8367 uint game_get_cd_used_space(char *path)
8371 char use_path[512] = "";
8372 char sub_path[512] = "";
8373 WIN32_FIND_DATA find;
8376 // recurse through all files and directories
8377 strcpy(use_path, path);
8378 strcat(use_path, "*.*");
8379 find_handle = FindFirstFile(use_path, &find);
8382 if(find_handle == INVALID_HANDLE_VALUE){
8388 // subdirectory. make sure to ignore . and ..
8389 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8391 strcpy(sub_path, path);
8392 strcat(sub_path, find.cFileName);
8393 strcat(sub_path, "\\");
8394 total += game_get_cd_used_space(sub_path);
8396 total += (uint)find.nFileSizeLow;
8398 } while(FindNextFile(find_handle, &find));
8401 FindClose(find_handle);
8413 // if volume_name is non-null, the CD name must match that
8414 int find_freespace_cd(char *volume_name)
8417 char oldpath[MAX_PATH];
8421 int volume_match = 0;
8425 GetCurrentDirectory(MAX_PATH, oldpath);
8427 for (i = 0; i < 26; i++)
8433 path[0] = (char)('A'+i);
8434 if (GetDriveType(path) == DRIVE_CDROM) {
8436 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8437 nprintf(("CD", "CD volume: %s\n", volume));
8439 // check for any CD volume
8440 int volume1_present = 0;
8441 int volume2_present = 0;
8442 int volume3_present = 0;
8444 char full_check[512] = "";
8446 // look for setup.exe
8447 strcpy(full_check, path);
8448 strcat(full_check, "setup.exe");
8449 find_handle = _findfirst(full_check, &find);
8450 if(find_handle != -1){
8451 volume1_present = 1;
8452 _findclose(find_handle);
8455 // look for intro.mve
8456 strcpy(full_check, path);
8457 strcat(full_check, "intro.mve");
8458 find_handle = _findfirst(full_check, &find);
8459 if(find_handle != -1){
8460 volume2_present = 1;
8461 _findclose(find_handle);
8464 // look for endpart1.mve
8465 strcpy(full_check, path);
8466 strcat(full_check, "endpart1.mve");
8467 find_handle = _findfirst(full_check, &find);
8468 if(find_handle != -1){
8469 volume3_present = 1;
8470 _findclose(find_handle);
8473 // see if we have the specific CD we're looking for
8474 if ( volume_name ) {
8476 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8480 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8484 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8488 if ( volume1_present || volume2_present || volume3_present ) {
8493 // 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
8494 if ( volume_match ){
8496 // 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
8497 if(volume2_present || volume3_present) {
8498 // first step - check to make sure its a cdrom
8499 if(GetDriveType(path) != DRIVE_CDROM){
8503 #if !defined(OEM_BUILD)
8504 // oem not on 80 min cds, so dont check tha size
8506 uint used_space = game_get_cd_used_space(path);
8507 if(used_space < CD_SIZE_72_MINUTE_MAX){
8510 #endif // !defined(OEM_BUILD)
8518 #endif // RELEASE_REAL
8524 SetCurrentDirectory(oldpath);
8533 int set_cdrom_path(int drive_num)
8537 if (drive_num < 0) { //no CD
8539 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8542 strcpy(Game_CDROM_dir,""); //set directory
8546 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8562 i = find_freespace_cd();
8564 rval = set_cdrom_path(i);
8568 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8570 nprintf(("CD", "FreeSpace CD not found\n"));
8578 int Last_cd_label_found = 0;
8579 char Last_cd_label[256];
8581 int game_cd_changed()
8588 if ( strlen(Game_CDROM_dir) == 0 ) {
8592 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8594 if ( found != Last_cd_label_found ) {
8595 Last_cd_label_found = found;
8597 mprintf(( "CD '%s' was inserted\n", label ));
8600 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8604 if ( Last_cd_label_found ) {
8605 if ( !stricmp( Last_cd_label, label )) {
8606 //mprintf(( "CD didn't change\n" ));
8608 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8612 // none found before, none found now.
8613 //mprintf(( "still no CD...\n" ));
8617 Last_cd_label_found = found;
8619 strcpy( Last_cd_label, label );
8621 strcpy( Last_cd_label, "" );
8632 // check if _any_ FreeSpace2 CDs are in the drive
8633 // return: 1 => CD now in drive
8634 // 0 => Could not find CD, they refuse to put it in the drive
8635 int game_do_cd_check(char *volume_name)
8637 #if !defined(GAME_CD_CHECK)
8643 int num_attempts = 0;
8644 int refresh_files = 0;
8646 int path_set_ok, popup_rval;
8648 cd_drive_num = find_freespace_cd(volume_name);
8649 path_set_ok = set_cdrom_path(cd_drive_num);
8650 if ( path_set_ok ) {
8652 if ( refresh_files ) {
8664 // no CD found, so prompt user
8665 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8667 if ( popup_rval != 1 ) {
8672 if ( num_attempts++ > 5 ) {
8683 // check if _any_ FreeSpace2 CDs are in the drive
8684 // return: 1 => CD now in drive
8685 // 0 => Could not find CD, they refuse to put it in the drive
8686 int game_do_cd_check_specific(char *volume_name, int cdnum)
8691 int num_attempts = 0;
8692 int refresh_files = 0;
8694 int path_set_ok, popup_rval;
8696 cd_drive_num = find_freespace_cd(volume_name);
8697 path_set_ok = set_cdrom_path(cd_drive_num);
8698 if ( path_set_ok ) {
8700 if ( refresh_files ) {
8711 // no CD found, so prompt user
8712 #if defined(DVD_MESSAGE_HACK)
8713 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8715 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8718 if ( popup_rval != 1 ) {
8723 if ( num_attempts++ > 5 ) {
8733 // only need to do this in RELEASE_REAL
8734 int game_do_cd_mission_check(char *filename)
8740 fs_builtin_mission *m = game_find_builtin_mission(filename);
8742 // check for changed CD
8743 if(game_cd_changed()){
8748 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8752 // not builtin, so do a general check (any FS2 CD will do)
8754 return game_do_cd_check();
8757 // does not have any CD requirement, do a general check
8758 if(strlen(m->cd_volume) <= 0){
8759 return game_do_cd_check();
8763 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8765 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8768 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8772 return game_do_cd_check();
8775 // did we find the cd?
8776 if(find_freespace_cd(m->cd_volume) >= 0){
8780 // make sure the volume exists
8781 int num_attempts = 0;
8782 int refresh_files = 0;
8784 int path_set_ok, popup_rval;
8786 cd_drive_num = find_freespace_cd(m->cd_volume);
8787 path_set_ok = set_cdrom_path(cd_drive_num);
8788 if ( path_set_ok ) {
8790 if ( refresh_files ) {
8797 // no CD found, so prompt user
8798 #if defined(DVD_MESSAGE_HACK)
8799 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8801 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8805 if ( popup_rval != 1 ) {
8810 if ( num_attempts++ > 5 ) {
8822 // ----------------------------------------------------------------
8824 // CDROM detection code END
8826 // ----------------------------------------------------------------
8828 // ----------------------------------------------------------------
8830 // Language Autodetection stuff
8833 // this layout order must match Lcl_languages in localize.cpp in order for the
8834 // correct language to be detected
8835 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
8837 1366105450, // English
8839 589986744, // English
8841 -1132430286, // German
8845 // default setting is "-1" to use config file with English as fall back
8846 // DO NOT change the default setting here or something uncouth might happen
8847 // in the localization code
8853 // try and open the file to verify
8854 CFILE *detect = cfopen("font01.vf", "rb");
8856 // will use default setting if something went wrong
8861 // get the long checksum of the file
8863 cfseek(detect, 0, SEEK_SET);
8864 cf_chksum_long(detect, &file_checksum);
8868 // now compare the checksum/filesize against known #'s
8869 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8870 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8875 // notify if a match was not found, include detected checksum
8876 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8877 printf("Using default language...\n\n");
8883 // End Auto Lang stuff
8885 // ----------------------------------------------------------------
8887 // ----------------------------------------------------------------
8888 // SHIPS TBL VERIFICATION STUFF
8891 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8892 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8893 #define NUM_SHIPS_TBL_CHECKSUMS 3
8895 #define NUM_SHIPS_TBL_CHECKSUMS 1
8899 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8900 1696074201, // FS2 demo
8903 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8904 1603375034, // FS1 DEMO
8907 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8908 -129679197, // FS1 Full 1.06 (US)
8909 7762567, // FS1 SilentThreat
8910 1555372475 // FS1 Full 1.06 (German)
8914 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8915 -463907578, // US - beta 1
8916 1696074201, // FS2 demo
8919 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8920 // -1022810006, // 1.0 FULL
8921 -1254285366 // 1.2 FULL (German)
8925 void verify_ships_tbl()
8929 Game_ships_tbl_valid = 1;
8935 // detect if the packfile exists
8936 CFILE *detect = cfopen("ships.tbl", "rb");
8937 Game_ships_tbl_valid = 0;
8941 Game_ships_tbl_valid = 0;
8945 // get the long checksum of the file
8947 cfseek(detect, 0, SEEK_SET);
8948 cf_chksum_long(detect, &file_checksum);
8952 // now compare the checksum/filesize against known #'s
8953 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8954 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8955 Game_ships_tbl_valid = 1;
8962 DCF(shipspew, "display the checksum for the current ships.tbl")
8965 CFILE *detect = cfopen("ships.tbl", "rb");
8966 // get the long checksum of the file
8968 cfseek(detect, 0, SEEK_SET);
8969 cf_chksum_long(detect, &file_checksum);
8972 dc_printf("%d", file_checksum);
8975 // ----------------------------------------------------------------
8976 // WEAPONS TBL VERIFICATION STUFF
8979 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8980 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8981 #define NUM_WEAPONS_TBL_CHECKSUMS 3
8983 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8987 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8988 -266420030, // demo 1
8991 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8992 -1246928725, // FS1 DEMO
8995 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8996 -834598107, // FS1 1.06 Full (US)
8997 -1652231417, // FS1 SilentThreat
8998 720209793 // FS1 1.06 Full (German)
9002 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9003 141718090, // US - beta 1
9004 -266420030, // demo 1
9007 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9008 // 399297860, // 1.0 FULL
9009 -553984927 // 1.2 FULL (german)
9013 void verify_weapons_tbl()
9017 Game_weapons_tbl_valid = 1;
9023 // detect if the packfile exists
9024 CFILE *detect = cfopen("weapons.tbl", "rb");
9025 Game_weapons_tbl_valid = 0;
9029 Game_weapons_tbl_valid = 0;
9033 // get the long checksum of the file
9035 cfseek(detect, 0, SEEK_SET);
9036 cf_chksum_long(detect, &file_checksum);
9040 // now compare the checksum/filesize against known #'s
9041 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
9042 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
9043 Game_weapons_tbl_valid = 1;
9050 DCF(wepspew, "display the checksum for the current weapons.tbl")
9053 CFILE *detect = cfopen("weapons.tbl", "rb");
9054 // get the long checksum of the file
9056 cfseek(detect, 0, SEEK_SET);
9057 cf_chksum_long(detect, &file_checksum);
9060 dc_printf("%d", file_checksum);
9063 // if the game is running using hacked data
9064 int game_hacked_data()
9067 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
9075 void display_title_screen()
9077 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
9078 ///int title_bitmap;
9081 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
9082 if (title_bitmap == -1) {
9088 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9089 extern void d3d_start_frame();
9095 gr_set_bitmap(title_bitmap);
9102 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9103 extern void d3d_stop_frame();
9111 bm_unload(title_bitmap);
9112 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
9115 // return true if the game is running with "low memory", which is less than 48MB
9116 bool game_using_low_mem()
9118 if (Use_low_mem == 0) {