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.33 2003/08/03 15:57:00 taylor
19 * simpler mouse usage; default ini settings in os_init(); cleanup
21 * Revision 1.32 2003/06/19 11:51:41 taylor
22 * adjustments to memory leak fixes
24 * Revision 1.31 2003/06/11 18:30:32 taylor
27 * Revision 1.30 2003/06/03 04:00:39 taylor
28 * Polish language support (Janusz Dziemidowicz)
30 * Revision 1.29 2003/05/25 02:30:42 taylor
33 * Revision 1.28 2003/05/18 03:55:30 taylor
34 * automatic language selection support
36 * Revision 1.27 2003/03/03 04:54:44 theoddone33
37 * Commit Taylor's ShowFPS fix
39 * Revision 1.26 2003/02/20 17:41:07 theoddone33
40 * Userdir patch from Taylor Richards
42 * Revision 1.25 2003/01/30 19:54:10 relnev
43 * ini config option for the frames per second counter (Taylor Richards)
45 * Revision 1.24 2002/08/31 01:39:13 theoddone33
46 * Speed up the renderer a tad
48 * Revision 1.23 2002/08/04 02:31:00 relnev
49 * make numlock not overlap with pause
51 * Revision 1.22 2002/08/02 23:07:03 relnev
52 * don't access the mouse in standalone mode
54 * Revision 1.21 2002/07/28 05:05:08 relnev
55 * removed some old stuff
57 * Revision 1.20 2002/07/24 00:20:41 relnev
60 * Revision 1.19 2002/06/17 06:33:08 relnev
61 * ryan's struct patch for gcc 2.95
63 * Revision 1.18 2002/06/16 04:46:33 relnev
64 * set up correct checksums for demo
66 * Revision 1.17 2002/06/09 04:41:17 relnev
67 * added copyright header
69 * Revision 1.16 2002/06/09 03:16:04 relnev
72 * removed unneeded asm, old sdl 2d setup.
74 * fixed crash caused by opengl_get_region.
76 * Revision 1.15 2002/06/05 08:05:28 relnev
77 * stub/warning removal.
79 * reworked the sound code.
81 * Revision 1.14 2002/06/05 04:03:32 relnev
82 * finished cfilesystem.
84 * removed some old code.
86 * fixed mouse save off-by-one.
90 * Revision 1.13 2002/06/02 04:26:34 relnev
93 * Revision 1.12 2002/06/02 00:31:35 relnev
94 * implemented osregistry
96 * Revision 1.11 2002/06/01 09:00:34 relnev
97 * silly debug memmanager
99 * Revision 1.10 2002/06/01 07:12:32 relnev
100 * a few NDEBUG updates.
102 * removed a few warnings.
104 * Revision 1.9 2002/05/31 03:05:59 relnev
107 * Revision 1.8 2002/05/29 02:52:32 theoddone33
108 * Enable OpenGL renderer
110 * Revision 1.7 2002/05/28 08:52:03 relnev
111 * implemented two assembly stubs.
113 * cleaned up a few warnings.
115 * added a little demo hackery to make it progress a little farther.
117 * Revision 1.6 2002/05/28 06:28:20 theoddone33
118 * Filesystem mods, actually reads some data files now
120 * Revision 1.5 2002/05/28 04:07:28 theoddone33
121 * New graphics stubbing arrangement
123 * Revision 1.4 2002/05/27 22:46:52 theoddone33
124 * Remove more undefined symbols
126 * Revision 1.3 2002/05/26 23:31:18 relnev
127 * added a few files that needed to be compiled
129 * freespace.cpp: now compiles
131 * Revision 1.2 2002/05/07 03:16:44 theoddone33
132 * The Great Newline Fix
134 * Revision 1.1.1.1 2002/05/03 03:28:09 root
138 * 201 6/16/00 3:15p Jefff
139 * sim of the year dvd version changes, a few german soty localization
142 * 200 11/03/99 11:06a Jefff
145 * 199 10/26/99 5:07p Jamest
146 * fixed jeffs dumb debug code
148 * 198 10/25/99 5:53p Jefff
149 * call control_config_common_init() on startup
151 * 197 10/14/99 10:18a Daveb
152 * Fixed incorrect CD checking problem on standalone server.
154 * 196 10/13/99 9:22a Daveb
155 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
156 * related to movies. Fixed launcher spawning from PXO screen.
158 * 195 10/06/99 11:05a Jefff
159 * new oem upsell 3 hotspot coords
161 * 194 10/06/99 10:31a Jefff
164 * 193 10/01/99 9:10a Daveb
167 * 192 9/15/99 4:57a Dave
168 * Updated ships.tbl checksum
170 * 191 9/15/99 3:58a Dave
171 * Removed framerate warning at all times.
173 * 190 9/15/99 3:16a Dave
174 * Remove mt-011.fs2 from the builtin mission list.
176 * 189 9/15/99 1:45a Dave
177 * Don't init joystick on standalone. Fixed campaign mode on standalone.
178 * Fixed no-score-report problem in TvT
180 * 188 9/14/99 6:08a Dave
181 * Updated (final) single, multi, and campaign list.
183 * 187 9/14/99 3:26a Dave
184 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
185 * respawn-too-early problem. Made a few crash points safe.
187 * 186 9/13/99 4:52p Dave
190 * 185 9/12/99 8:09p Dave
191 * Fixed problem where skip-training button would cause mission messages
192 * not to get paged out for the current mission.
194 * 184 9/10/99 11:53a Dave
195 * Shutdown graphics before sound to eliminate apparent lockups when
196 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
198 * 183 9/09/99 11:40p Dave
199 * Handle an Assert() in beam code. Added supernova sounds. Play the right
200 * 2 end movies properly, based upon what the player did in the mission.
202 * 182 9/08/99 10:29p Dave
203 * Make beam sound pausing and unpausing much safer.
205 * 181 9/08/99 10:01p Dave
206 * Make sure game won't run in a drive's root directory. Make sure
207 * standalone routes suqad war messages properly to the host.
209 * 180 9/08/99 3:22p Dave
210 * Updated builtin mission list.
212 * 179 9/08/99 12:01p Jefff
213 * fixed Game_builtin_mission_list typo on Training-2.fs2
215 * 178 9/08/99 9:48a Andsager
216 * Add force feedback for engine wash.
218 * 177 9/07/99 4:01p Dave
219 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
220 * does everything properly (setting up address when binding). Remove
221 * black rectangle background from UI_INPUTBOX.
223 * 176 9/13/99 2:40a Dave
224 * Comment in full 80 minute CD check for RELEASE_REAL builds.
226 * 175 9/06/99 6:38p Dave
227 * Improved CD detection code.
229 * 174 9/06/99 1:30a Dave
230 * Intermediate checkin. Started on enforcing CD-in-drive to play the
233 * 173 9/06/99 1:16a Dave
234 * Make sure the user sees the intro movie.
236 * 172 9/04/99 8:00p Dave
237 * Fixed up 1024 and 32 bit movie support.
239 * 171 9/03/99 1:32a Dave
240 * CD checking by act. Added support to play 2 cutscenes in a row
241 * seamlessly. Fixed super low level cfile bug related to files in the
242 * root directory of a CD. Added cheat code to set campaign mission # in
245 * 170 9/01/99 10:49p Dave
246 * Added nice SquadWar checkbox to the client join wait screen.
248 * 169 9/01/99 10:14a Dave
251 * 168 8/29/99 4:51p Dave
252 * Fixed damaged checkin.
254 * 167 8/29/99 4:18p Andsager
255 * New "burst" limit for friendly damage. Also credit more damage done
256 * against large friendly ships.
258 * 166 8/27/99 6:38p Alanl
259 * crush the blasted repeating messages bug
261 * 164 8/26/99 9:09p Dave
262 * Force framerate check in everything but a RELEASE_REAL build.
264 * 163 8/26/99 9:45a Dave
265 * First pass at easter eggs and cheats.
267 * 162 8/24/99 8:55p Dave
268 * Make sure nondimming pixels work properly in tech menu.
270 * 161 8/24/99 1:49a Dave
271 * Fixed client-side afterburner stuttering. Added checkbox for no version
272 * checking on PXO join. Made button info passing more friendly between
275 * 160 8/22/99 5:53p Dave
276 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
277 * instead of ship designations for multiplayer players.
279 * 159 8/22/99 1:19p Dave
280 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
281 * which d3d cards are detected.
283 * 158 8/20/99 2:09p Dave
284 * PXO banner cycling.
286 * 157 8/19/99 10:59a Dave
287 * Packet loss detection.
289 * 156 8/19/99 10:12a Alanl
290 * preload mission-specific messages on machines greater than 48MB
292 * 155 8/16/99 4:04p Dave
293 * Big honking checkin.
295 * 154 8/11/99 5:54p Dave
296 * Fixed collision problem. Fixed standalone ghost problem.
298 * 153 8/10/99 7:59p Jefff
301 * 152 8/10/99 6:54p Dave
302 * Mad optimizations. Added paging to the nebula effect.
304 * 151 8/10/99 3:44p Jefff
305 * loads Intelligence information on startup
307 * 150 8/09/99 3:47p Dave
308 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
309 * non-nebula missions.
311 * 149 8/09/99 2:21p Andsager
312 * Fix patching from multiplayer direct to launcher update tab.
314 * 148 8/09/99 10:36a Dave
315 * Version info for game.
317 * 147 8/06/99 9:46p Dave
318 * Hopefully final changes for the demo.
320 * 146 8/06/99 3:34p Andsager
321 * Make title version info "(D)" -> "D" show up nicely
323 * 145 8/06/99 2:59p Adamp
324 * Fixed NT launcher/update problem.
326 * 144 8/06/99 1:52p Dave
327 * Bumped up MAX_BITMAPS for the demo.
329 * 143 8/06/99 12:17p Andsager
330 * Demo: down to just 1 demo dog
332 * 142 8/05/99 9:39p Dave
333 * Yet another new checksum.
335 * 141 8/05/99 6:19p Dave
336 * New demo checksums.
338 * 140 8/05/99 5:31p Andsager
339 * Up demo version 1.01
341 * 139 8/05/99 4:22p Andsager
342 * No time limit on upsell screens. Reverse order of display of upsell
345 * 138 8/05/99 4:17p Dave
346 * Tweaks to client interpolation.
348 * 137 8/05/99 3:52p Danw
350 * 136 8/05/99 3:01p Danw
352 * 135 8/05/99 2:43a Anoop
353 * removed duplicate definition.
355 * 134 8/05/99 2:13a Dave
358 * 133 8/05/99 2:05a Dave
361 * 132 8/05/99 1:22a Andsager
364 * 131 8/04/99 9:51p Andsager
365 * Add title screen to demo
367 * 130 8/04/99 6:47p Jefff
368 * fixed link error resulting from #ifdefs
370 * 129 8/04/99 6:26p Dave
371 * Updated ship tbl checksum.
373 * 128 8/04/99 5:40p Andsager
374 * Add multiple demo dogs
376 * 127 8/04/99 5:36p Andsager
377 * Show upsell screens at end of demo campaign before returning to main
380 * 126 8/04/99 11:42a Danw
381 * tone down EAX reverb
383 * 125 8/04/99 11:23a Dave
384 * Updated demo checksums.
386 * 124 8/03/99 11:02p Dave
387 * Maybe fixed sync problems in multiplayer.
389 * 123 8/03/99 6:21p Jefff
392 * 122 8/03/99 3:44p Andsager
393 * Launch laucher if trying to run FS without first having configured
396 * 121 8/03/99 12:45p Dave
399 * 120 8/02/99 9:13p Dave
402 * 119 7/30/99 10:31p Dave
403 * Added comm menu to the configurable hud files.
405 * 118 7/30/99 5:17p Andsager
406 * first fs2demo checksums
408 * 117 7/29/99 3:09p Anoop
410 * 116 7/29/99 12:05a Dave
411 * Nebula speed optimizations.
413 * 115 7/27/99 8:59a Andsager
414 * Make major, minor version consistent for all builds. Only show major
415 * and minor for launcher update window.
417 * 114 7/26/99 5:50p Dave
418 * Revised ingame join. Better? We'll see....
420 * 113 7/26/99 5:27p Andsager
421 * Add training mission as builtin to demo build
423 * 112 7/24/99 1:54p Dave
424 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
427 * 111 7/22/99 4:00p Dave
428 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
430 * 110 7/21/99 8:10p Dave
431 * First run of supernova effect.
433 * 109 7/20/99 1:49p Dave
434 * Peter Drake build. Fixed some release build warnings.
436 * 108 7/19/99 2:26p Andsager
437 * set demo multiplayer missions
439 * 107 7/18/99 5:19p Dave
440 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
442 * 106 7/16/99 1:50p Dave
443 * 8 bit aabitmaps. yay.
445 * 105 7/15/99 3:07p Dave
446 * 32 bit detection support. Mouse coord commandline.
448 * 104 7/15/99 2:13p Dave
449 * Added 32 bit detection.
451 * 103 7/15/99 9:20a Andsager
452 * FS2_DEMO initial checkin
454 * 102 7/14/99 11:02a Dave
455 * Skill level default back to easy. Blech.
457 * 101 7/09/99 5:54p Dave
458 * Seperated cruiser types into individual types. Added tons of new
459 * briefing icons. Campaign screen.
461 * 100 7/08/99 4:43p Andsager
462 * New check for sparky_hi and print if not found.
464 * 99 7/08/99 10:53a Dave
465 * New multiplayer interpolation scheme. Not 100% done yet, but still
466 * better than the old way.
468 * 98 7/06/99 4:24p Dave
469 * Mid-level checkin. Starting on some potentially cool multiplayer
472 * 97 7/06/99 3:35p Andsager
473 * Allow movie to play before red alert mission.
475 * 96 7/03/99 5:50p Dave
476 * Make rotated bitmaps draw properly in padlock views.
478 * 95 7/02/99 9:55p Dave
479 * Player engine wash sound.
481 * 94 7/02/99 4:30p Dave
482 * Much more sophisticated lightning support.
484 * 93 6/29/99 7:52p Dave
485 * Put in exception handling in FS2.
487 * 92 6/22/99 9:37p Dave
488 * Put in pof spewing.
490 * 91 6/16/99 4:06p Dave
491 * New pilot info popup. Added new draw-bitmap-as-poly function.
493 * 90 6/15/99 1:56p Andsager
494 * For release builds, allow start up in high res only with
497 * 89 6/15/99 9:34a Dave
498 * Fixed key checking in single threaded version of the stamp notification
501 * 88 6/09/99 2:55p Andsager
502 * Allow multiple asteroid subtypes (of large, medium, small) and follow
505 * 87 6/08/99 1:14a Dave
506 * Multi colored hud test.
508 * 86 6/04/99 9:52a Dave
509 * Fixed some rendering problems.
511 * 85 6/03/99 10:15p Dave
512 * Put in temporary main hall screen.
514 * 84 6/02/99 6:18p Dave
515 * Fixed TNT lockup problems! Wheeeee!
517 * 83 6/01/99 3:52p Dave
518 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
519 * dead popup, pxo find player popup, pxo private room popup.
521 * 82 5/26/99 1:28p Jasenw
522 * changed coords for loading ani
524 * 81 5/26/99 11:46a Dave
525 * Added ship-blasting lighting and made the randomization of lighting
526 * much more customizable.
528 * 80 5/24/99 5:45p Dave
529 * Added detail levels to the nebula, with a decent speedup. Split nebula
530 * lightning into its own section.
548 #include "systemvars.h"
553 #include "starfield.h"
554 #include "lighting.h"
559 #include "fireballs.h"
563 #include "floating.h"
564 #include "gamesequence.h"
566 #include "optionsmenu.h"
567 #include "playermenu.h"
568 #include "trainingmenu.h"
569 #include "techmenu.h"
572 #include "hudmessage.h"
574 #include "missiongoals.h"
575 #include "missionparse.h"
580 #include "multiutil.h"
581 #include "multimsgs.h"
585 #include "freespace.h"
586 #include "managepilot.h"
588 #include "contexthelp.h"
591 #include "missionbrief.h"
592 #include "missiondebrief.h"
594 #include "missionshipchoice.h"
596 #include "hudconfig.h"
597 #include "controlsconfig.h"
598 #include "missionmessage.h"
599 #include "missiontraining.h"
601 #include "hudtarget.h"
603 #include "eventmusic.h"
604 #include "animplay.h"
605 #include "missionweaponchoice.h"
606 #include "missionlog.h"
607 #include "audiostr.h"
609 #include "missioncampaign.h"
611 #include "missionhotkey.h"
612 #include "objectsnd.h"
613 #include "cmeasure.h"
615 #include "linklist.h"
616 #include "shockwave.h"
617 #include "afterburner.h"
622 #include "stand_gui.h"
623 #include "pcxutils.h"
624 #include "hudtargetbox.h"
625 #include "multi_xfer.h"
626 #include "hudescort.h"
627 #include "multiutil.h"
630 #include "multiteamselect.h"
633 #include "readyroom.h"
634 #include "mainhallmenu.h"
635 #include "multilag.h"
637 #include "particle.h"
639 #include "multi_ingame.h"
640 #include "snazzyui.h"
641 #include "asteroid.h"
642 #include "popupdead.h"
643 #include "multi_voice.h"
644 #include "missioncmdbrief.h"
645 #include "redalert.h"
646 #include "gameplayhelp.h"
647 #include "multilag.h"
648 #include "staticrand.h"
649 #include "multi_pmsg.h"
650 #include "levelpaging.h"
651 #include "observer.h"
652 #include "multi_pause.h"
653 #include "multi_endgame.h"
654 #include "cutscenes.h"
655 #include "multi_respawn.h"
657 #include "multi_obj.h"
658 #include "multi_log.h"
660 #include "localize.h"
661 #include "osregistry.h"
662 #include "barracks.h"
663 #include "missionpause.h"
665 #include "alphacolors.h"
666 #include "objcollide.h"
669 #include "neblightning.h"
670 #include "shipcontrails.h"
673 #include "multi_dogfight.h"
674 #include "multi_rate.h"
675 #include "muzzleflash.h"
679 #include "mainhalltemp.h"
680 #include "exceptionhandler.h"
684 #include "supernova.h"
685 #include "hudshield.h"
686 // #include "names.h"
688 #include "missionloopbrief.h"
692 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
698 // 1.00.04 5/26/98 MWA -- going final (12 pm)
699 // 1.00.03 5/26/98 MWA -- going final (3 am)
700 // 1.00.02 5/25/98 MWA -- going final
701 // 1.00.01 5/25/98 MWA -- going final
702 // 0.90 5/21/98 MWA -- getting ready for final.
703 // 0.10 4/9/98. Set by MK.
705 // Demo version: (obsolete since DEMO codebase split from tree)
706 // 0.03 4/10/98 AL. Interplay rev
707 // 0.02 4/8/98 MK. Increased when this system was modified.
708 // 0.01 4/7/98? AL. First release to Interplay QA.
711 // 1.00 5/28/98 AL. First release to Interplay QA.
713 void game_level_init(int seed = -1);
714 void game_post_level_init();
715 void game_do_frame();
716 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
717 void game_reset_time();
718 void game_show_framerate(); // draws framerate in lower right corner
720 int Game_no_clear = 0;
722 int Pofview_running = 0;
723 int Nebedit_running = 0;
725 typedef struct big_expl_flash {
726 float max_flash_intensity; // max intensity
727 float cur_flash_intensity; // cur intensity
728 int flash_start; // start time
731 #define FRAME_FILTER 16
733 #define DEFAULT_SKILL_LEVEL 1
734 int Game_skill_level = DEFAULT_SKILL_LEVEL;
736 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
737 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
739 #define EXE_FNAME ("fs2.exe")
740 #define LAUNCHER_FNAME ("freespace2.exe")
742 // JAS: Code for warphole camera.
743 // Needs to be cleaned up.
744 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
745 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
746 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
747 matrix Camera_orient = IDENTITY_MATRIX;
748 float Camera_damping = 1.0f;
749 float Camera_time = 0.0f;
750 float Warpout_time = 0.0f;
751 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
752 int Warpout_sound = -1;
754 int Use_joy_mouse = 0;
755 int Use_palette_flash = 1;
757 int Use_fullscreen_at_startup = 0;
759 int Show_area_effect = 0;
760 object *Last_view_target = NULL;
762 int dogfight_blown = 0;
765 float frametimes[FRAME_FILTER];
766 float frametotal = 0.0f;
770 int Show_framerate = 0;
772 int Show_framerate = 1;
775 int Framerate_cap = 120;
778 int Show_target_debug_info = 0;
779 int Show_target_weapons = 0;
783 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
786 int Debug_octant = -1;
788 fix Game_time_compression = F1_0;
790 // if the ships.tbl the player has is valid
791 int Game_ships_tbl_valid = 0;
793 // if the weapons.tbl the player has is valid
794 int Game_weapons_tbl_valid = 0;
798 extern int Player_attacking_enabled;
802 int Pre_player_entry;
804 int Fred_running = 0;
805 char Game_current_mission_filename[MAX_FILENAME_LEN];
806 int game_single_step = 0;
807 int last_single_step=0;
809 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
810 extern int MSG_WINDOW_Y_START;
811 extern int MSG_WINDOW_HEIGHT;
813 int game_zbuffer = 1;
814 //static int Game_music_paused;
815 static int Game_paused;
819 #define EXPIRE_BAD_CHECKSUM 1
820 #define EXPIRE_BAD_TIME 2
822 extern void ssm_init();
823 extern void ssm_level_init();
824 extern void ssm_process();
826 // static variable to contain the time this version was built
827 // commented out for now until
828 // I figure out how to get the username into the file
829 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
831 // defines and variables used for dumping frame for making trailers.
833 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
834 int Debug_dump_trigger = 0;
835 int Debug_dump_frame_count;
836 int Debug_dump_frame_num = 0;
837 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
840 // amount of time to wait after the player has died before we display the death died popup
841 #define PLAYER_DIED_POPUP_WAIT 2500
842 int Player_died_popup_wait = -1;
843 int Player_multi_died_check = -1;
845 // builtin mission list stuff
847 int Game_builtin_mission_count = 6;
848 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
849 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
850 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
851 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
852 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
853 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 #elif defined(FS1_DEMO)
857 int Game_builtin_mission_count = 5;
858 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
859 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
860 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
861 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
862 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
863 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
865 #elif defined(PD_BUILD)
866 int Game_builtin_mission_count = 4;
867 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
868 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
869 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
870 { "sm1-01", (FSB_FROM_VOLITION), "" },
871 { "sm1-05", (FSB_FROM_VOLITION), "" },
873 #elif defined(MULTIPLAYER_BETA)
874 int Game_builtin_mission_count = 17;
875 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
877 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
890 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
891 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
892 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
893 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
895 #elif defined(OEM_BUILD)
896 int Game_builtin_mission_count = 17;
897 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
898 // oem version - act 1 only
899 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
902 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
903 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
904 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
905 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
906 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
907 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
908 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
909 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
910 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
911 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
912 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
913 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
914 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
915 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
916 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
917 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
919 #elif defined(MAKE_FS1)
920 int Game_builtin_mission_count = 125;
921 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
922 // single player campaign
923 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
926 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
927 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
928 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
929 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
930 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
931 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
932 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
933 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
934 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
935 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
938 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
939 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
940 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
941 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
942 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
943 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
944 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
945 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
946 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
947 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
950 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
951 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
952 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
953 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
954 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
955 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
956 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
957 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
958 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
961 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
967 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
968 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
969 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
970 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
973 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
974 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
976 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
984 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
985 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
987 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
988 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
989 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
990 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
991 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
992 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
993 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
994 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
996 // SilentThreat missions
997 // Main SilentThreat campaign
998 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE), "" },
1000 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1001 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1002 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1003 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1004 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1005 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1006 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1007 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1008 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1009 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1010 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1011 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1013 // SilentThreat Part 1 - multi-coop
1014 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1016 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1017 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1018 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1020 // SilentThreat Part 2 - multi-coop
1021 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1023 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1024 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1025 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1027 // SilentThreat Part 3 - multi-coop
1028 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1030 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1031 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1032 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1034 // SilentThreat Part 4 - multi-coop
1035 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1037 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1038 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1039 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1041 // multiplayer missions
1042 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1043 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1044 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1045 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1046 // user supplied missions
1047 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1048 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1049 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1050 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1051 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1052 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1053 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1054 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1055 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1056 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1057 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1058 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1059 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1060 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1061 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1062 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1063 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1064 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1065 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1066 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1067 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1068 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1069 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1070 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1071 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1072 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1073 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1074 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1075 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1076 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1077 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1078 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1081 int Game_builtin_mission_count = 92;
1082 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1083 // single player campaign
1084 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
1087 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1088 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1089 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1090 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1091 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1092 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1093 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1094 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1095 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1096 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1097 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1098 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1099 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1100 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1101 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1102 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1103 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1104 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1105 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1108 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1109 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1110 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1111 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1112 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1113 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1114 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1115 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1116 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1117 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1120 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1121 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1122 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1123 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1124 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1125 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1126 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1127 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1128 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1129 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1130 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1131 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1133 // multiplayer missions
1136 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1137 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1138 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1141 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1142 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1143 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1144 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1147 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1148 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1149 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1150 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1151 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1152 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1153 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1154 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1155 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1156 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1157 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1158 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1159 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1160 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1161 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1162 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1163 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1164 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1165 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1166 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1167 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1168 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1169 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1170 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1171 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1172 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1173 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1174 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1177 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1178 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1179 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1180 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1181 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1182 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1183 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1184 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1185 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1186 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1189 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1190 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1191 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1192 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1193 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1198 // Internal function prototypes
1199 void game_maybe_draw_mouse(float frametime);
1200 void init_animating_pointer();
1201 void load_animating_pointer(char *filename, int dx, int dy);
1202 void unload_animating_pointer();
1203 void game_do_training_checks();
1204 void game_shutdown(void);
1205 void game_show_event_debug(float frametime);
1206 void game_event_debug_init();
1208 void demo_upsell_show_screens();
1209 void game_start_subspace_ambient_sound();
1210 void game_stop_subspace_ambient_sound();
1211 void verify_ships_tbl();
1212 void verify_weapons_tbl();
1213 void display_title_screen();
1215 // loading background filenames
1216 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1217 "LoadingBG", // GR_640
1218 "2_LoadingBG" // GR_1024
1222 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1223 "Loading.ani", // GR_640
1224 "2_Loading.ani" // GR_1024
1227 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1228 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1236 #elif defined(OEM_BUILD)
1237 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1247 char Game_CDROM_dir[MAX_PATH_LEN];
1250 // How much RAM is on this machine. Set in WinMain
1251 uint Freespace_total_ram = 0;
1254 float Game_flash_red = 0.0f;
1255 float Game_flash_green = 0.0f;
1256 float Game_flash_blue = 0.0f;
1257 float Sun_spot = 0.0f;
1258 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1260 // game shudder stuff (in ms)
1261 int Game_shudder_time = -1;
1262 int Game_shudder_total = 0;
1263 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1266 sound_env Game_sound_env;
1267 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1268 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1270 int Game_sound_env_update_timestamp;
1272 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1275 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1277 fs_builtin_mission *game_find_builtin_mission(char *filename)
1281 // look through all existing builtin missions
1282 for(idx=0; idx<Game_builtin_mission_count; idx++){
1283 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1284 return &Game_builtin_mission_list[idx];
1292 int game_get_default_skill_level()
1294 return DEFAULT_SKILL_LEVEL;
1298 void game_flash_reset()
1300 Game_flash_red = 0.0f;
1301 Game_flash_green = 0.0f;
1302 Game_flash_blue = 0.0f;
1304 Big_expl_flash.max_flash_intensity = 0.0f;
1305 Big_expl_flash.cur_flash_intensity = 0.0f;
1306 Big_expl_flash.flash_start = 0;
1309 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1310 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1312 void game_framerate_check_init()
1314 // zero critical time
1315 Gf_critical_time = 0.0f;
1318 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1319 // if this is a glide card
1320 if(gr_screen.mode == GR_GLIDE){
1322 extern GrHwConfiguration hwconfig;
1325 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1326 Gf_critical = 15.0f;
1330 Gf_critical = 10.0f;
1335 Gf_critical = 15.0f;
1338 // d3d. only care about good cards here I guess (TNT)
1340 Gf_critical = 15.0f;
1343 // if this is a glide card
1344 if(gr_screen.mode == GR_GLIDE){
1346 extern GrHwConfiguration hwconfig;
1349 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1350 Gf_critical = 25.0f;
1354 Gf_critical = 20.0f;
1359 Gf_critical = 25.0f;
1362 // d3d. only care about good cards here I guess (TNT)
1364 Gf_critical = 25.0f;
1369 extern float Framerate;
1370 void game_framerate_check()
1374 // if the current framerate is above the critical level, add frametime
1375 if(Framerate >= Gf_critical){
1376 Gf_critical_time += flFrametime;
1379 if(!Show_framerate){
1383 // display if we're above the critical framerate
1384 if(Framerate < Gf_critical){
1385 gr_set_color_fast(&Color_bright_red);
1386 gr_string(200, y_start, "Framerate warning");
1391 // display our current pct of good frametime
1392 if(f2fl(Missiontime) >= 0.0f){
1393 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1396 gr_set_color_fast(&Color_bright_green);
1398 gr_set_color_fast(&Color_bright_red);
1401 gr_printf(200, y_start, "%d%%", (int)pct);
1408 // Adds a flash effect. These can be positive or negative.
1409 // The range will get capped at around -1 to 1, so stick
1410 // with a range like that.
1411 void game_flash( float r, float g, float b )
1413 Game_flash_red += r;
1414 Game_flash_green += g;
1415 Game_flash_blue += b;
1417 if ( Game_flash_red < -1.0f ) {
1418 Game_flash_red = -1.0f;
1419 } else if ( Game_flash_red > 1.0f ) {
1420 Game_flash_red = 1.0f;
1423 if ( Game_flash_green < -1.0f ) {
1424 Game_flash_green = -1.0f;
1425 } else if ( Game_flash_green > 1.0f ) {
1426 Game_flash_green = 1.0f;
1429 if ( Game_flash_blue < -1.0f ) {
1430 Game_flash_blue = -1.0f;
1431 } else if ( Game_flash_blue > 1.0f ) {
1432 Game_flash_blue = 1.0f;
1437 // Adds a flash for Big Ship explosions
1438 // cap range from 0 to 1
1439 void big_explosion_flash(float flash)
1441 Big_expl_flash.flash_start = timestamp(1);
1445 } else if (flash < 0.0f) {
1449 Big_expl_flash.max_flash_intensity = flash;
1450 Big_expl_flash.cur_flash_intensity = 0.0f;
1453 // Amount to diminish palette towards normal, per second.
1454 #define DIMINISH_RATE 0.75f
1455 #define SUN_DIMINISH_RATE 6.00f
1459 float sn_glare_scale = 1.7f;
1462 dc_get_arg(ARG_FLOAT);
1463 sn_glare_scale = Dc_arg_float;
1466 float Supernova_last_glare = 0.0f;
1467 void game_sunspot_process(float frametime)
1471 float Sun_spot_goal = 0.0f;
1474 sn_stage = supernova_active();
1476 // sunspot differently based on supernova stage
1478 // approaching. player still in control
1481 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1484 light_get_global_dir(&light_dir, 0);
1486 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1489 // scale it some more
1490 dot = dot * (0.5f + (pct * 0.5f));
1493 Sun_spot_goal += (dot * sn_glare_scale);
1496 // draw the sun glow
1497 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1498 // draw the glow for this sun
1499 stars_draw_sun_glow(0);
1502 Supernova_last_glare = Sun_spot_goal;
1505 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1508 Sun_spot_goal = 0.9f;
1509 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1511 if(Sun_spot_goal > 1.0f){
1512 Sun_spot_goal = 1.0f;
1515 Sun_spot_goal *= sn_glare_scale;
1516 Supernova_last_glare = Sun_spot_goal;
1519 // fade to white. display dead popup
1522 Supernova_last_glare += (2.0f * flFrametime);
1523 if(Supernova_last_glare > 2.0f){
1524 Supernova_last_glare = 2.0f;
1527 Sun_spot_goal = Supernova_last_glare;
1534 // check sunspots for all suns
1535 n_lights = light_get_global_count();
1538 for(idx=0; idx<n_lights; idx++){
1539 //(vector *eye_pos, matrix *eye_orient)
1540 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1543 light_get_global_dir(&light_dir, idx);
1545 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1547 Sun_spot_goal += (float)pow(dot,85.0f);
1549 // draw the glow for this sun
1550 stars_draw_sun_glow(idx);
1552 Sun_spot_goal = 0.0f;
1558 Sun_spot_goal = 0.0f;
1562 float dec_amount = frametime*SUN_DIMINISH_RATE;
1564 if ( Sun_spot < Sun_spot_goal ) {
1565 Sun_spot += dec_amount;
1566 if ( Sun_spot > Sun_spot_goal ) {
1567 Sun_spot = Sun_spot_goal;
1569 } else if ( Sun_spot > Sun_spot_goal ) {
1570 Sun_spot -= dec_amount;
1571 if ( Sun_spot < Sun_spot_goal ) {
1572 Sun_spot = Sun_spot_goal;
1578 // Call once a frame to diminish the
1579 // flash effect to 0.
1580 void game_flash_diminish(float frametime)
1582 float dec_amount = frametime*DIMINISH_RATE;
1584 if ( Game_flash_red > 0.0f ) {
1585 Game_flash_red -= dec_amount;
1586 if ( Game_flash_red < 0.0f )
1587 Game_flash_red = 0.0f;
1589 Game_flash_red += dec_amount;
1590 if ( Game_flash_red > 0.0f )
1591 Game_flash_red = 0.0f;
1594 if ( Game_flash_green > 0.0f ) {
1595 Game_flash_green -= dec_amount;
1596 if ( Game_flash_green < 0.0f )
1597 Game_flash_green = 0.0f;
1599 Game_flash_green += dec_amount;
1600 if ( Game_flash_green > 0.0f )
1601 Game_flash_green = 0.0f;
1604 if ( Game_flash_blue > 0.0f ) {
1605 Game_flash_blue -= dec_amount;
1606 if ( Game_flash_blue < 0.0f )
1607 Game_flash_blue = 0.0f;
1609 Game_flash_blue += dec_amount;
1610 if ( Game_flash_blue > 0.0f )
1611 Game_flash_blue = 0.0f;
1614 // update big_explosion_cur_flash
1615 #define TIME_UP 1500
1616 #define TIME_DOWN 2500
1617 int duration = TIME_UP + TIME_DOWN;
1618 int time = timestamp_until(Big_expl_flash.flash_start);
1619 if (time > -duration) {
1621 if (time < TIME_UP) {
1622 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1625 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1629 if ( Use_palette_flash ) {
1631 // static int or=0, og=0, ob=0;
1633 // Change the 200 to change the color range of colors.
1634 r = fl2i( Game_flash_red*128.0f );
1635 g = fl2i( Game_flash_green*128.0f );
1636 b = fl2i( Game_flash_blue*128.0f );
1638 if ( Sun_spot > 0.0f ) {
1639 r += fl2i(Sun_spot*128.0f);
1640 g += fl2i(Sun_spot*128.0f);
1641 b += fl2i(Sun_spot*128.0f);
1644 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1645 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1646 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1647 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1650 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1651 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1652 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1654 if ( (r!=0) || (g!=0) || (b!=0) ) {
1655 gr_flash( r, g, b );
1657 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1668 void game_level_close()
1670 // De-Initialize the game subsystems
1671 event_music_level_close();
1672 game_stop_looped_sounds();
1674 obj_snd_level_close(); // uninit object-linked persistant sounds
1675 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1676 anim_level_close(); // stop and clean up any anim instances
1677 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1678 shockwave_level_close();
1679 fireball_level_close();
1681 mission_event_shutdown();
1682 asteroid_level_close();
1683 model_cache_reset(); // Reset/free all the model caching stuff
1684 flak_level_close(); // unload flak stuff
1685 neb2_level_close(); // shutdown gaseous nebula stuff
1688 mflash_level_close();
1690 audiostream_unpause_all();
1695 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1696 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1697 void game_level_init(int seed)
1699 // seed the random number generator
1701 // if no seed was passed, seed the generator either from the time value, or from the
1702 // netgame security flags -- ensures that all players in multiplayer game will have the
1703 // same randon number sequence (with static rand functions)
1704 if ( Game_mode & GM_NORMAL ) {
1705 Game_level_seed = time(NULL);
1707 Game_level_seed = Netgame.security;
1710 // mwa 9/17/98 -- maybe this assert isn't needed????
1711 Assert( !(Game_mode & GM_MULTIPLAYER) );
1712 Game_level_seed = seed;
1714 srand( Game_level_seed );
1716 // semirand function needs to get re-initted every time in multiplayer
1717 if ( Game_mode & GM_MULTIPLAYER ){
1723 Key_normal_game = (Game_mode & GM_NORMAL);
1726 Game_shudder_time = -1;
1728 // Initialize the game subsystems
1729 // timestamp_reset(); // Must be inited before everything else
1731 game_reset_time(); // resets time, and resets saved time too
1733 obj_init(); // Must be inited before the other systems
1734 model_free_all(); // Free all existing models
1735 mission_brief_common_init(); // Free all existing briefing/debriefing text
1736 weapon_level_init();
1737 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1739 player_level_init();
1740 shipfx_flash_init(); // Init the ship gun flash system.
1741 game_flash_reset(); // Reset the flash effect
1742 particle_init(); // Reset the particle system
1746 shield_hit_init(); // Initialize system for showing shield hits
1747 radar_mission_init();
1748 mission_init_goals();
1751 obj_snd_level_init(); // init object-linked persistant sounds
1753 shockwave_level_init();
1754 afterburner_level_init();
1755 scoring_level_init( &Player->stats );
1757 asteroid_level_init();
1758 control_config_clear_used_status();
1759 collide_ship_ship_sounds_init();
1761 Pre_player_entry = 1; // Means the player has not yet entered.
1762 Entry_delay_time = 0; // Could get overwritten in mission read.
1763 fireball_preload(); // page in warphole bitmaps
1765 flak_level_init(); // initialize flak - bitmaps, etc
1766 ct_level_init(); // initialize ships contrails, etc
1767 awacs_level_init(); // initialize AWACS
1768 beam_level_init(); // initialize beam weapons
1769 mflash_level_init();
1771 supernova_level_init();
1773 // multiplayer dogfight hack
1776 shipfx_engine_wash_level_init();
1780 Last_view_target = NULL;
1785 // campaign wasn't ended
1786 Campaign_ended_in_mission = 0;
1789 // called when a mission is over -- does server specific stuff.
1790 void freespace_stop_mission()
1793 Game_mode &= ~GM_IN_MISSION;
1796 // called at frame interval to process networking stuff
1797 void game_do_networking()
1799 Assert( Net_player != NULL );
1800 if (!(Game_mode & GM_MULTIPLAYER)){
1804 // see if this player should be reading/writing data. Bit is set when at join
1805 // screen onward until quits back to main menu.
1806 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1810 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1813 multi_pause_do_frame();
1818 // Loads the best palette for this level, based
1819 // on nebula color and hud color. You could just call palette_load_table with
1820 // the appropriate filename, but who wants to do that.
1821 void game_load_palette()
1823 char palette_filename[1024];
1825 // We only use 3 hud colors right now
1827 Assert( HUD_config.main_color >= 0 );
1828 Assert( HUD_config.main_color <= 2 );
1831 Assert( Mission_palette >= 0 );
1832 Assert( Mission_palette <= 98 );
1835 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1836 strcpy( palette_filename, NOX("gamepalette-subspace") );
1838 sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1841 mprintf(( "Loading palette %s\n", palette_filename ));
1843 palette_load_table(palette_filename);
1845 strcpy( palette_filename, NOX("gamepalette-subspace") );
1847 mprintf(( "Loading palette %s\n", palette_filename ));
1851 void game_post_level_init()
1853 // Stuff which gets called after mission is loaded. Because player isn't created until
1854 // after mission loads, some things must get initted after the level loads
1856 model_level_post_init();
1859 hud_setup_escort_list();
1860 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1866 game_event_debug_init();
1869 training_mission_init();
1870 asteroid_create_all();
1872 game_framerate_check_init();
1876 // An estimate as to how high the count passed to game_loading_callback will go.
1877 // This is just a guess, it seems to always be about the same. The count is
1878 // proportional to the code being executed, not the time, so this works good
1879 // for a bar, assuming the code does about the same thing each time you
1880 // load a level. You can find this value by looking at the return value
1881 // of game_busy_callback(NULL), which I conveniently print out to the
1882 // debug output window with the '=== ENDING LOAD ==' stuff.
1883 //#define COUNT_ESTIMATE 3706
1884 #define COUNT_ESTIMATE 1111
1886 int Game_loading_callback_inited = 0;
1888 int Game_loading_background = -1;
1889 anim * Game_loading_ani = NULL;
1890 anim_instance *Game_loading_ani_instance;
1891 int Game_loading_frame=-1;
1893 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1895 #if defined(FS1_DEMO)
1897 #elif defined(MAKE_FS1)
1908 // This gets called 10x per second and count is the number of times
1909 // game_busy() has been called since the current callback function
1911 void game_loading_callback(int count)
1913 game_do_networking();
1915 Assert( Game_loading_callback_inited==1 );
1916 Assert( Game_loading_ani != NULL );
1918 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1919 if ( framenum > Game_loading_ani->total_frames-1 ) {
1920 framenum = Game_loading_ani->total_frames-1;
1921 } else if ( framenum < 0 ) {
1926 while ( Game_loading_frame < framenum ) {
1927 Game_loading_frame++;
1928 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1932 if ( cbitmap > -1 ) {
1933 if ( Game_loading_background > -1 ) {
1934 gr_set_bitmap( Game_loading_background );
1938 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1939 gr_set_bitmap( cbitmap );
1940 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1942 bm_release(cbitmap);
1948 void game_loading_callback_init()
1950 Assert( Game_loading_callback_inited==0 );
1952 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1954 common_set_interface_palette("InterfacePalette"); // set the interface palette
1958 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1959 Assert( Game_loading_ani != NULL );
1960 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1961 Assert( Game_loading_ani_instance != NULL );
1962 Game_loading_frame = -1;
1964 Game_loading_callback_inited = 1;
1966 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1971 void game_loading_callback_close()
1973 Assert( Game_loading_callback_inited==1 );
1975 // Make sure bar shows all the way over.
1976 game_loading_callback(COUNT_ESTIMATE);
1978 int real_count = game_busy_callback( NULL );
1981 Game_loading_callback_inited = 0;
1984 mprintf(( "=================== ENDING LOAD ================\n" ));
1985 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1986 mprintf(( "================================================\n" ));
1988 // to remove warnings in release build
1992 free_anim_instance(Game_loading_ani_instance);
1993 Game_loading_ani_instance = NULL;
1994 anim_free(Game_loading_ani);
1995 Game_loading_ani = NULL;
1997 bm_release( Game_loading_background );
1998 common_free_interface_palette(); // restore game palette
1999 Game_loading_background = -1;
2001 gr_set_font( FONT1 );
2004 // Update the sound environment (ie change EAX settings based on proximity to large ships)
2006 void game_maybe_update_sound_environment()
2008 // do nothing for now
2011 // Assign the sound environment for the game, based on the current mission
2013 void game_assign_sound_environment()
2016 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
2017 Game_sound_env.id = SND_ENV_DRUGGED;
2018 Game_sound_env.volume = 0.800f;
2019 Game_sound_env.damping = 1.188f;
2020 Game_sound_env.decay = 6.392f;
2022 } else if (Num_asteroids > 30) {
2023 Game_sound_env.id = SND_ENV_AUDITORIUM;
2024 Game_sound_env.volume = 0.603f;
2025 Game_sound_env.damping = 0.5f;
2026 Game_sound_env.decay = 4.279f;
2029 Game_sound_env = Game_default_sound_env;
2033 Game_sound_env = Game_default_sound_env;
2034 Game_sound_env_update_timestamp = timestamp(1);
2037 // function which gets called before actually entering the mission. It is broken down into a funciton
2038 // since it will get called in one place from a single player game and from another place for
2039 // a multiplayer game
2040 void freespace_mission_load_stuff()
2042 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2043 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2044 if(!(Game_mode & GM_STANDALONE_SERVER)){
2046 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2048 game_loading_callback_init();
2050 event_music_level_init(); // preloads the first 2 seconds for each event music track
2053 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2056 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2059 ship_assign_sound_all(); // assign engine sounds to ships
2060 game_assign_sound_environment(); // assign the sound environment for this mission
2063 // call function in missionparse.cpp to fixup player/ai stuff.
2064 mission_parse_fixup_players();
2067 // Load in all the bitmaps for this level
2072 game_loading_callback_close();
2074 // the only thing we need to call on the standalone for now.
2076 // call function in missionparse.cpp to fixup player/ai stuff.
2077 mission_parse_fixup_players();
2079 // Load in all the bitmaps for this level
2085 uint load_mission_load;
2086 uint load_post_level_init;
2087 uint load_mission_stuff;
2089 // tells the server to load the mission and initialize structures
2090 int game_start_mission()
2092 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2094 load_gl_init = time(NULL);
2096 load_gl_init = time(NULL) - load_gl_init;
2098 if (Game_mode & GM_MULTIPLAYER) {
2099 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2101 // clear multiplayer stats
2102 init_multiplayer_stats();
2105 load_mission_load = time(NULL);
2106 if (mission_load()) {
2107 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2108 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2109 gameseq_post_event(GS_EVENT_MAIN_MENU);
2111 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2116 load_mission_load = time(NULL) - load_mission_load;
2118 // If this is a red alert mission in campaign mode, bash wingman status
2119 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2120 red_alert_bash_wingman_status();
2123 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2124 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2125 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2127 game_load_palette();
2131 load_post_level_init = time(NULL);
2132 game_post_level_init();
2133 load_post_level_init = time(NULL) - load_post_level_init;
2137 void Do_model_timings_test();
2138 Do_model_timings_test();
2142 load_mission_stuff = time(NULL);
2143 freespace_mission_load_stuff();
2144 load_mission_stuff = time(NULL) - load_mission_stuff;
2149 int Interface_framerate = 0;
2152 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2153 DCF_BOOL( show_framerate, Show_framerate )
2154 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2155 DCF_BOOL( show_target_weapons, Show_target_weapons )
2156 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2157 DCF_BOOL( sound, Sound_enabled )
2158 DCF_BOOL( zbuffer, game_zbuffer )
2159 DCF_BOOL( shield_system, New_shield_system )
2160 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2161 DCF_BOOL( player_attacking, Player_attacking_enabled )
2162 DCF_BOOL( show_waypoints, Show_waypoints )
2163 DCF_BOOL( show_area_effect, Show_area_effect )
2164 DCF_BOOL( show_net_stats, Show_net_stats )
2165 DCF_BOOL( log, Log_debug_output_to_file )
2166 DCF_BOOL( training_msg_method, Training_msg_method )
2167 DCF_BOOL( show_player_pos, Show_player_pos )
2168 DCF_BOOL(i_framerate, Interface_framerate )
2170 DCF(show_mem,"Toggles showing mem usage")
2173 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2174 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2175 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2176 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2182 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2184 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2185 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2189 DCF(show_cpu,"Toggles showing cpu usage")
2192 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2193 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2194 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2195 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2201 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2203 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2204 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2211 // AL 4-8-98: always allow players to display their framerate
2214 DCF_BOOL( show_framerate, Show_framerate )
2221 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2224 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2225 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2226 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2227 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2229 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" );
2230 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2232 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2235 DCF(palette_flash,"Toggles palette flash effect on/off")
2238 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2239 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2240 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2241 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2243 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2244 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2247 int Use_low_mem = 0;
2249 DCF(low_mem,"Uses low memory settings regardless of RAM")
2252 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2253 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2254 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2255 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2257 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2258 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2260 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2266 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2269 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2270 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2271 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2272 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2274 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2275 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2276 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2280 int Framerate_delay = 0;
2282 float Freespace_gamma = 1.0f;
2284 DCF(gamma,"Sets Gamma factor")
2287 dc_get_arg(ARG_FLOAT|ARG_NONE);
2288 if ( Dc_arg_type & ARG_FLOAT ) {
2289 Freespace_gamma = Dc_arg_float;
2291 dc_printf( "Gamma reset to 1.0f\n" );
2292 Freespace_gamma = 1.0f;
2294 if ( Freespace_gamma < 0.1f ) {
2295 Freespace_gamma = 0.1f;
2296 } else if ( Freespace_gamma > 5.0f ) {
2297 Freespace_gamma = 5.0f;
2299 gr_set_gamma(Freespace_gamma);
2301 char tmp_gamma_string[32];
2302 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2303 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2307 dc_printf( "Usage: gamma <float>\n" );
2308 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2309 Dc_status = 0; // don't print status if help is printed. Too messy.
2313 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2322 Game_current_mission_filename[0] = 0;
2324 // seed the random number generator
2325 Game_init_seed = time(NULL);
2326 srand( Game_init_seed );
2328 Framerate_delay = 0;
2334 extern void bm_init();
2340 // Initialize the timer before the os
2348 GetCurrentDirectory(1024, whee);
2351 getcwd (whee, 1024);
2354 strcat(whee, EXE_FNAME);
2356 //Initialize the libraries
2357 s1 = timer_get_milliseconds();
2358 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2361 e1 = timer_get_milliseconds();
2363 // time a bunch of cfopens
2365 s2 = timer_get_milliseconds();
2367 for(int idx=0; idx<10000; idx++){
2368 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2373 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2375 e2 = timer_get_milliseconds();
2378 if (Is_standalone) {
2379 std_init_standalone();
2381 os_init( Osreg_class_name, Osreg_app_name );
2382 os_set_title(Osreg_title);
2385 // initialize localization module. Make sure this is down AFTER initialzing OS.
2386 // int t1 = timer_get_milliseconds();
2387 lcl_init( detect_lang() );
2389 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2391 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2394 // verify that he has a valid weapons.tbl
2395 verify_weapons_tbl();
2397 // Output version numbers to registry for auto patching purposes
2398 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2399 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2400 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2402 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2403 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2404 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2407 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2410 #if defined (PLAT_UNIX) && defined(RELEASE_REAL)
2411 // show the FPS counter if the config file says so
2412 Show_framerate = os_config_read_uint( NULL, NOX("ShowFPS"), 0 );
2415 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2416 Asteroids_enabled = 1;
2419 /////////////////////////////
2421 /////////////////////////////
2426 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2427 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2429 if (!stricmp(ptr, NOX("no sound"))) {
2430 Cmdline_freespace_no_sound = 1;
2432 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2434 } else if (!stricmp(ptr, NOX("EAX"))) {
2439 if (!Is_standalone) {
2440 snd_init(use_a3d, use_eax);
2442 /////////////////////////////
2444 /////////////////////////////
2446 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2449 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);
2451 // fire up the UpdateLauncher executable
2453 PROCESS_INFORMATION pi;
2455 memset( &si, 0, sizeof(STARTUPINFO) );
2458 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2459 NULL, // pointer to command line string
2460 NULL, // pointer to process security attributes
2461 NULL, // pointer to thread security attributes
2462 FALSE, // handle inheritance flag
2463 CREATE_DEFAULT_ERROR_MODE, // creation flags
2464 NULL, // pointer to new environment block
2465 NULL, // pointer to current directory name
2466 &si, // pointer to STARTUPINFO
2467 &pi // pointer to PROCESS_INFORMATION
2470 // If the Launcher could not be started up, let the user know
2472 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2481 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2483 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);
2491 // check for hi res pack file
2492 int has_sparky_hi = 0;
2494 // check if sparky_hi exists -- access mode 0 means does file exist
2495 #ifndef MAKE_FS1 // shoudn't have it so don't check
2498 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2501 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2505 // see if we've got 32 bit in the string
2506 if(strstr(ptr, "32 bit")){
2513 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2515 // always 640 for E3
2516 gr_init(GR_640, GR_GLIDE);
2518 // regular or hi-res ?
2520 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2522 if(strstr(ptr, NOX("(1024x768)"))){
2524 gr_init(GR_1024, GR_GLIDE);
2526 gr_init(GR_640, GR_GLIDE);
2529 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2531 // always 640 for E3
2533 gr_init(GR_640, GR_DIRECT3D, depth);
2535 // regular or hi-res ?
2537 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2539 if(strstr(ptr, NOX("(1024x768)"))){
2543 gr_init(GR_1024, GR_DIRECT3D, depth);
2547 gr_init(GR_640, GR_DIRECT3D, depth);
2553 if ( Use_fullscreen_at_startup && !Is_standalone) {
2554 gr_init(GR_640, GR_DIRECTDRAW);
2556 gr_init(GR_640, GR_SOFTWARE);
2559 if ( !Is_standalone ) {
2560 gr_init(GR_640, GR_DIRECTDRAW);
2562 gr_init(GR_640, GR_SOFTWARE);
2567 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2568 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2569 gr_init(GR_1024, GR_OPENGL);
2571 gr_init(GR_640, GR_OPENGL);
2575 gr_init(GR_640, GR_SOFTWARE);
2577 #endif // !PLAT_UNIX
2580 extern int Gr_inited;
2581 if(trying_d3d && !Gr_inited){
2583 extern char Device_init_error[512];
2584 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2593 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2594 Freespace_gamma = (float)atof(ptr);
2595 if ( Freespace_gamma == 0.0f ) {
2596 Freespace_gamma = 1.80f;
2597 } else if ( Freespace_gamma < 0.1f ) {
2598 Freespace_gamma = 0.1f;
2599 } else if ( Freespace_gamma > 5.0f ) {
2600 Freespace_gamma = 5.0f;
2602 char tmp_gamma_string[32];
2603 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2604 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2606 gr_set_gamma(Freespace_gamma);
2608 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2611 display_title_screen();
2615 // attempt to load up master tracker registry info (login and password)
2616 Multi_tracker_id = -1;
2618 // pxo login and password
2619 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2621 nprintf(("Network","Error reading in PXO login data\n"));
2622 strcpy(Multi_tracker_login,"");
2624 strcpy(Multi_tracker_login,ptr);
2626 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2628 nprintf(("Network","Error reading PXO password\n"));
2629 strcpy(Multi_tracker_passwd,"");
2631 strcpy(Multi_tracker_passwd,ptr);
2634 // pxo squad name and password
2635 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2637 nprintf(("Network","Error reading in PXO squad name\n"));
2638 strcpy(Multi_tracker_squad_name, "");
2640 strcpy(Multi_tracker_squad_name, ptr);
2643 // If less than 48MB of RAM, use low memory model.
2646 (Freespace_total_ram < 48*1024*1024) ||
2649 mprintf(( "Using normal memory settings...\n" ));
2650 bm_set_low_mem(1); // Use every other frame of bitmaps
2652 mprintf(( "Using high memory settings...\n" ));
2653 bm_set_low_mem(0); // Use all frames of bitmaps
2656 // load non-darkening pixel defs
2657 palman_load_pixels();
2659 // hud shield icon stuff
2660 hud_shield_game_init();
2662 control_config_common_init(); // sets up localization stuff in the control config
2668 gamesnd_parse_soundstbl();
2673 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2678 player_controls_init();
2681 //if(!Is_standalone){
2689 ship_init(); // read in ships.tbl
2691 mission_campaign_init(); // load in the default campaign
2693 // navmap_init(); // init the navigation map system
2694 context_help_init();
2695 techroom_intel_init(); // parse species.tbl, load intel info
2697 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2698 init_animating_pointer();
2700 mission_brief_common_init(); // Mark all the briefing structures as empty.
2701 gr_font_init(); // loads up all fonts
2703 neb2_init(); // fullneb stuff
2707 player_tips_init(); // helpful tips
2710 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2711 pilot_load_pic_list();
2712 pilot_load_squad_pic_list();
2714 load_animating_pointer(NOX("cursor"), 0, 0);
2716 // initialize alpha colors
2717 alpha_colors_init();
2720 // Game_music_paused = 0;
2727 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2728 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2730 mprintf(("cfile_init() took %d\n", e1 - s1));
2731 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2734 char transfer_text[128];
2736 float Start_time = 0.0f;
2738 float Framerate = 0.0f;
2740 float Timing_total = 0.0f;
2741 float Timing_render2 = 0.0f;
2742 float Timing_render3 = 0.0f;
2743 float Timing_flip = 0.0f;
2744 float Timing_clear = 0.0f;
2746 MONITOR(NumPolysDrawn);
2752 void game_get_framerate()
2754 char text[128] = "";
2756 if ( frame_int == -1 ) {
2758 for (i=0; i<FRAME_FILTER; i++ ) {
2759 frametimes[i] = 0.0f;
2764 frametotal -= frametimes[frame_int];
2765 frametotal += flFrametime;
2766 frametimes[frame_int] = flFrametime;
2767 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2769 if ( frametotal != 0.0 ) {
2770 if ( Framecount >= FRAME_FILTER )
2771 Framerate = FRAME_FILTER / frametotal;
2773 Framerate = Framecount / frametotal;
2774 sprintf( text, NOX("FPS: %.1f"), Framerate );
2776 sprintf( text, NOX("FPS: ?") );
2780 if (Show_framerate) {
2781 gr_set_color_fast(&HUD_color_debug);
2782 gr_string( 570, 2, text );
2786 void game_show_framerate()
2790 cur_time = f2fl(timer_get_approx_seconds());
2791 if (cur_time - Start_time > 30.0f) {
2792 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2793 Start_time += 1000.0f;
2796 //mprintf(( "%s\n", text ));
2799 if ( Debug_dump_frames )
2803 // possibly show control checking info
2804 control_check_indicate();
2806 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2807 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2808 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2809 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2812 if ( Show_cpu == 1 ) {
2817 dy = gr_get_font_height() + 1;
2819 gr_set_color_fast(&HUD_color_debug);
2823 extern int D3D_textures_in;
2824 extern int D3D_textures_in_frame;
2825 extern int Glide_textures_in;
2826 extern int Glide_textures_in_frame;
2827 extern int Glide_explosion_vram;
2828 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2830 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2832 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2836 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2838 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2840 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2842 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2844 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2849 extern int Num_pairs; // Number of object pairs that were checked.
2850 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2853 extern int Num_pairs_checked; // What percent of object pairs were checked.
2854 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2856 Num_pairs_checked = 0;
2860 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2863 if ( Timing_total > 0.01f ) {
2864 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2866 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2868 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2870 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2872 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2882 dy = gr_get_font_height() + 1;
2884 gr_set_color_fast(&HUD_color_debug);
2887 extern int TotalRam;
2888 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2893 extern int Model_ram;
2894 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2898 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2900 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2902 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2906 extern int D3D_textures_in;
2907 extern int Glide_textures_in;
2908 extern int Glide_textures_in_frame;
2909 extern int Glide_explosion_vram;
2910 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2912 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2914 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2921 if ( Show_player_pos ) {
2925 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));
2928 MONITOR_INC(NumPolys, modelstats_num_polys);
2929 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2930 MONITOR_INC(NumVerts, modelstats_num_verts );
2932 modelstats_num_polys = 0;
2933 modelstats_num_polys_drawn = 0;
2934 modelstats_num_verts = 0;
2935 modelstats_num_sortnorms = 0;
2939 void game_show_standalone_framerate()
2941 float frame_rate=30.0f;
2942 if ( frame_int == -1 ) {
2944 for (i=0; i<FRAME_FILTER; i++ ) {
2945 frametimes[i] = 0.0f;
2950 frametotal -= frametimes[frame_int];
2951 frametotal += flFrametime;
2952 frametimes[frame_int] = flFrametime;
2953 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2955 if ( frametotal != 0.0 ) {
2956 if ( Framecount >= FRAME_FILTER ){
2957 frame_rate = FRAME_FILTER / frametotal;
2959 frame_rate = Framecount / frametotal;
2962 std_set_standalone_fps(frame_rate);
2966 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2967 void game_show_time_left()
2971 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2972 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2973 // checking how much time is left
2975 if ( Mission_end_time == -1 ){
2979 diff = f2i(Mission_end_time - Missiontime);
2980 // be sure to bash to 0. diff could be negative on frame that we quit mission
2985 hud_set_default_color();
2986 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2989 //========================================================================================
2990 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2991 //========================================================================================
2995 DCF(ai_pause,"Pauses ai")
2998 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2999 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
3000 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
3001 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
3004 obj_init_all_ships_physics();
3007 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
3008 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
3011 DCF(single_step,"Single steps the game")
3014 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3015 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
3016 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
3017 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
3019 last_single_step = 0; // Make so single step waits a frame before stepping
3022 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
3023 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
3026 DCF_BOOL(physics_pause, physics_paused)
3027 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
3028 DCF_BOOL(ai_firing, Ai_firing_enabled )
3030 // Create some simple aliases to these commands...
3031 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
3032 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
3033 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
3034 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
3035 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
3038 //========================================================================================
3039 //========================================================================================
3042 void game_training_pause_do()
3046 key = game_check_key();
3048 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
3055 void game_increase_skill_level()
3058 if (Game_skill_level >= NUM_SKILL_LEVELS){
3059 Game_skill_level = 0;
3063 int Player_died_time;
3065 int View_percent = 100;
3068 DCF(view, "Sets the percent of the 3d view to render.")
3071 dc_get_arg(ARG_INT);
3072 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
3073 View_percent = Dc_arg_int;
3075 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
3081 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
3085 dc_printf("View is set to %d%%\n", View_percent );
3090 // Set the clip region for the 3d rendering window
3091 void game_set_view_clip()
3093 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
3094 // Set the clip region for the letterbox "dead view"
3095 int yborder = gr_screen.max_h/4;
3097 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
3098 // J.S. I've changed my ways!! See the new "no constants" code!!!
3099 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
3101 // Set the clip region for normal view
3102 if ( View_percent >= 100 ) {
3105 int xborder, yborder;
3107 if ( View_percent < 5 ) {
3111 float fp = i2fl(View_percent)/100.0f;
3112 int fi = fl2i(fl_sqrt(fp)*100.0f);
3113 if ( fi > 100 ) fi=100;
3115 xborder = ( gr_screen.max_w*(100-fi) )/200;
3116 yborder = ( gr_screen.max_h*(100-fi) )/200;
3118 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
3124 void show_debug_stuff()
3127 int laser_count = 0, missile_count = 0;
3129 for (i=0; i<MAX_OBJECTS; i++) {
3130 if (Objects[i].type == OBJ_WEAPON){
3131 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
3133 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
3139 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
3142 extern int Tool_enabled;
3147 int tst_bitmap = -1;
3149 float tst_offset, tst_offset_total;
3152 void game_tst_frame_pre()
3160 g3_rotate_vertex(&v, &tst_pos);
3161 g3_project_vertex(&v);
3164 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
3168 // big ship? always tst
3170 // within 3000 meters
3171 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
3175 // within 300 meters
3176 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
3183 void game_tst_frame()
3193 tst_time = time(NULL);
3195 // load the tst bitmap
3196 switch((int)frand_range(0.0f, 3.0)){
3198 tst_bitmap = bm_load("ig_jim");
3200 mprintf(("TST 0\n"));
3204 tst_bitmap = bm_load("ig_kan");
3206 mprintf(("TST 1\n"));
3210 tst_bitmap = bm_load("ig_jim");
3212 mprintf(("TST 2\n"));
3216 tst_bitmap = bm_load("ig_kan");
3218 mprintf(("TST 3\n"));
3227 // get the tst bitmap dimensions
3229 bm_get_info(tst_bitmap, &w, &h);
3232 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3234 snd_play(&Snds[SND_VASUDAN_BUP]);
3236 // tst x and direction
3240 tst_offset_total = (float)w;
3241 tst_offset = (float)w;
3243 tst_x = (float)gr_screen.max_w;
3244 tst_offset_total = (float)-w;
3245 tst_offset = (float)w;
3253 float diff = (tst_offset_total / 0.5f) * flFrametime;
3259 tst_offset -= fl_abs(diff);
3260 } else if(tst_mode == 2){
3263 tst_offset -= fl_abs(diff);
3267 gr_set_bitmap(tst_bitmap);
3268 gr_bitmap((int)tst_x, (int)tst_y);
3271 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3275 // if we passed the switch point
3276 if(tst_offset <= 0.0f){
3281 tst_stamp = timestamp(1000);
3282 tst_offset = fl_abs(tst_offset_total);
3293 void game_tst_mark(object *objp, ship *shipp)
3302 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3305 sip = &Ship_info[shipp->ship_info_index];
3312 tst_pos = objp->pos;
3313 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3319 extern void render_shields();
3321 void player_repair_frame(float frametime)
3323 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3325 for(idx=0;idx<MAX_PLAYERS;idx++){
3328 np = &Net_players[idx];
3330 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)){
3332 // don't rearm/repair if the player is dead or dying/departing
3333 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3334 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3339 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3340 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3346 #define NUM_FRAMES_TEST 300
3347 #define NUM_MIXED_SOUNDS 16
3348 void do_timing_test(float flFrametime)
3350 static int framecount = 0;
3351 static int test_running = 0;
3352 static float test_time = 0.0f;
3354 static int snds[NUM_MIXED_SOUNDS];
3357 if ( test_running ) {
3359 test_time += flFrametime;
3360 if ( framecount >= NUM_FRAMES_TEST ) {
3362 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3363 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3368 if ( Test_begin == 1 ) {
3374 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3377 // start looping digital sounds
3378 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3379 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3386 DCF(dcf_fov, "Change the field of view")
3389 dc_get_arg(ARG_FLOAT|ARG_NONE);
3390 if ( Dc_arg_type & ARG_NONE ) {
3391 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3392 dc_printf( "Zoom factor reset\n" );
3394 if ( Dc_arg_type & ARG_FLOAT ) {
3395 if (Dc_arg_float < 0.25f) {
3396 Viewer_zoom = 0.25f;
3397 dc_printf("Zoom factor pinned at 0.25.\n");
3398 } else if (Dc_arg_float > 1.25f) {
3399 Viewer_zoom = 1.25f;
3400 dc_printf("Zoom factor pinned at 1.25.\n");
3402 Viewer_zoom = Dc_arg_float;
3408 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3411 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3415 DCF(framerate_cap, "Sets the framerate cap")
3418 dc_get_arg(ARG_INT);
3419 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3420 Framerate_cap = Dc_arg_int;
3422 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3428 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3429 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3430 dc_printf("[n] must be from 1 to 120.\n");
3434 if ( Framerate_cap )
3435 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3437 dc_printf("There is no framerate cap currently active.\n");
3441 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3442 int Show_viewing_from_self = 0;
3444 void say_view_target()
3446 object *view_target;
3448 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3449 view_target = &Objects[Player_ai->target_objnum];
3451 view_target = Player_obj;
3453 if (Game_mode & GM_DEAD) {
3454 if (Player_ai->target_objnum != -1)
3455 view_target = &Objects[Player_ai->target_objnum];
3458 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3459 if (view_target != Player_obj){
3461 char *view_target_name = NULL;
3462 switch(Objects[Player_ai->target_objnum].type) {
3464 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3467 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3468 Viewer_mode &= ~VM_OTHER_SHIP;
3470 case OBJ_JUMP_NODE: {
3471 char jump_node_name[128];
3472 strcpy(jump_node_name, XSTR( "jump node", 184));
3473 view_target_name = jump_node_name;
3474 Viewer_mode &= ~VM_OTHER_SHIP;
3483 if ( view_target_name ) {
3484 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3485 Show_viewing_from_self = 1;
3488 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3489 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3490 Show_viewing_from_self = 1;
3492 if (Show_viewing_from_self)
3493 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3498 Last_view_target = view_target;
3502 float Game_hit_x = 0.0f;
3503 float Game_hit_y = 0.0f;
3505 // Reset at the beginning of each frame
3506 void game_whack_reset()
3512 // Apply a 2d whack to the player
3513 void game_whack_apply( float x, float y )
3515 // Do some force feedback
3516 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3522 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3525 // call to apply a "shudder"
3526 void game_shudder_apply(int time, float intensity)
3528 Game_shudder_time = timestamp(time);
3529 Game_shudder_total = time;
3530 Game_shudder_intensity = intensity;
3533 #define FF_SCALE 10000
3534 void apply_hud_shake(matrix *eye_orient)
3536 if (Viewer_obj == Player_obj) {
3537 physics_info *pi = &Player_obj->phys_info;
3545 // Make eye shake due to afterburner
3546 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3549 dtime = timestamp_until(pi->afterburner_decay);
3553 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3554 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3557 // Make eye shake due to engine wash
3559 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3562 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3563 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3565 // get the intensity
3566 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3570 vm_vec_rand_vec_quick(&rand_vec);
3573 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3577 // make hud shake due to shuddering
3578 if(Game_shudder_time != -1){
3579 // if the timestamp has elapsed
3580 if(timestamp_elapsed(Game_shudder_time)){
3581 Game_shudder_time = -1;
3583 // otherwise apply some shudder
3587 dtime = timestamp_until(Game_shudder_time);
3591 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));
3592 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));
3597 vm_angles_2_matrix(&tm, &tangles);
3598 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3599 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3600 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3601 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3606 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3608 // Player's velocity just before he blew up. Used to keep camera target moving.
3609 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3611 // Set eye_pos and eye_orient based on view mode.
3612 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3616 static int last_Viewer_mode = 0;
3617 static int last_Game_mode = 0;
3618 static int last_Viewer_objnum = -1;
3620 // This code is supposed to detect camera "cuts"... like going between
3623 // determine if we need to regenerate the nebula
3624 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3625 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3626 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3627 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3628 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3629 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3630 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3631 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3632 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3635 // regenerate the nebula
3639 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3640 //mprintf(( "************** Camera cut! ************\n" ));
3641 last_Viewer_mode = Viewer_mode;
3642 last_Game_mode = Game_mode;
3644 // Camera moved. Tell stars & debris to not do blurring.
3650 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3651 player_display_packlock_view();
3654 game_set_view_clip();
3656 if (Game_mode & GM_DEAD) {
3657 vector vec_to_deader, view_pos;
3660 Viewer_mode |= VM_DEAD_VIEW;
3662 if (Player_ai->target_objnum != -1) {
3663 int view_from_player = 1;
3665 if (Viewer_mode & VM_OTHER_SHIP) {
3666 // View from target.
3667 Viewer_obj = &Objects[Player_ai->target_objnum];
3669 last_Viewer_objnum = Player_ai->target_objnum;
3671 if ( Viewer_obj->type == OBJ_SHIP ) {
3672 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3673 view_from_player = 0;
3676 last_Viewer_objnum = -1;
3679 if ( view_from_player ) {
3680 // View target from player ship.
3682 *eye_pos = Player_obj->pos;
3683 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3684 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3687 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3689 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3690 dist += flFrametime * 16.0f;
3692 vm_vec_scale(&vec_to_deader, -dist);
3693 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3695 view_pos = Player_obj->pos;
3697 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3698 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3699 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3700 Dead_player_last_vel = Player_obj->phys_info.vel;
3701 //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));
3702 } else if (Player_ai->target_objnum != -1) {
3703 view_pos = Objects[Player_ai->target_objnum].pos;
3705 // Make camera follow explosion, but gradually slow down.
3706 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3707 view_pos = Player_obj->pos;
3708 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3709 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3712 *eye_pos = Dead_camera_pos;
3714 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3716 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3721 // if supernova shockwave
3722 if(supernova_camera_cut()){
3726 // call it dead view
3727 Viewer_mode |= VM_DEAD_VIEW;
3729 // set eye pos and orient
3730 supernova_set_view(eye_pos, eye_orient);
3732 // If already blown up, these other modes can override.
3733 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3734 Viewer_mode &= ~VM_DEAD_VIEW;
3736 Viewer_obj = Player_obj;
3738 if (Viewer_mode & VM_OTHER_SHIP) {
3739 if (Player_ai->target_objnum != -1){
3740 Viewer_obj = &Objects[Player_ai->target_objnum];
3741 last_Viewer_objnum = Player_ai->target_objnum;
3743 Viewer_mode &= ~VM_OTHER_SHIP;
3744 last_Viewer_objnum = -1;
3747 last_Viewer_objnum = -1;
3750 if (Viewer_mode & VM_EXTERNAL) {
3753 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3754 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3756 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3758 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3759 vm_vec_normalize(&eye_dir);
3760 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3763 // Modify the orientation based on head orientation.
3764 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3766 } else if ( Viewer_mode & VM_CHASE ) {
3769 if ( Viewer_obj->phys_info.speed < 0.1 )
3770 move_dir = Viewer_obj->orient.v.fvec;
3772 move_dir = Viewer_obj->phys_info.vel;
3773 vm_vec_normalize(&move_dir);
3776 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3777 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3778 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3779 vm_vec_normalize(&eye_dir);
3781 // JAS: I added the following code because if you slew up using
3782 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3783 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3784 // call because the up and the forward vector are the same. I fixed
3785 // it by adding in a fraction of the right vector all the time to the
3787 vector tmp_up = Viewer_obj->orient.v.uvec;
3788 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3790 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3793 // Modify the orientation based on head orientation.
3794 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3795 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3796 *eye_pos = Camera_pos;
3798 ship * shipp = &Ships[Player_obj->instance];
3800 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3801 vm_vec_normalize(&eye_dir);
3802 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3805 // get an eye position based upon the correct type of object
3806 switch(Viewer_obj->type){
3808 // make a call to get the eye point for the player object
3809 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3812 // make a call to get the eye point for the player object
3813 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3819 #ifdef JOHNS_DEBUG_CODE
3820 john_debug_stuff(&eye_pos, &eye_orient);
3826 apply_hud_shake(eye_orient);
3828 // setup neb2 rendering
3829 neb2_render_setup(eye_pos, eye_orient);
3833 extern void ai_debug_render_stuff();
3836 int Game_subspace_effect = 0;
3837 DCF_BOOL( subspace, Game_subspace_effect );
3839 // Does everything needed to render a frame
3840 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3844 g3_start_frame(game_zbuffer);
3845 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3847 // maybe offset the HUD (jitter stuff)
3848 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3849 HUD_set_offsets(Viewer_obj, !dont_offset);
3851 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3852 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3853 // must be done before ships are rendered
3854 if ( MULTIPLAYER_CLIENT ) {
3855 shield_point_multi_setup();
3858 if ( Game_subspace_effect ) {
3859 stars_draw(0,0,0,1);
3861 stars_draw(1,1,1,0);
3864 obj_render_all(obj_render);
3865 beam_render_all(); // render all beam weapons
3866 particle_render_all(); // render particles after everything else.
3867 trail_render_all(); // render missilie trails after everything else.
3868 mflash_render_all(); // render all muzzle flashes
3870 // Why do we not show the shield effect in these modes? Seems ok.
3871 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3875 // render nebula lightning
3878 // render local player nebula
3879 neb2_render_player();
3882 ai_debug_render_stuff();
3885 #ifndef RELEASE_REAL
3886 // game_framerate_check();
3890 extern void snd_spew_debug_info();
3891 snd_spew_debug_info();
3894 //================ END OF 3D RENDERING STUFF ====================
3898 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3899 hud_maybe_clear_head_area();
3900 anim_render_all(0, flFrametime);
3903 extern int Multi_display_netinfo;
3904 if(Multi_display_netinfo){
3905 extern void multi_display_netinfo();
3906 multi_display_netinfo();
3909 game_tst_frame_pre();
3912 do_timing_test(flFrametime);
3916 extern int OO_update_index;
3917 multi_rate_display(OO_update_index, 375, 0);
3922 extern void oo_display();
3929 //#define JOHNS_DEBUG_CODE 1
3931 #ifdef JOHNS_DEBUG_CODE
3932 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3934 //if ( keyd_pressed[KEY_LSHIFT] )
3936 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3938 model_subsystem *turret = tsys->system_info;
3940 if (turret->type == SUBSYSTEM_TURRET ) {
3941 vector v.fvec, v.uvec;
3942 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3944 ship_model_start(tobj);
3946 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3947 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3948 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3950 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3952 ship_model_stop(tobj);
3962 // following function for dumping frames for purposes of building trailers.
3965 // function to toggle state of dumping every frame into PCX when playing the game
3966 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3970 if ( Debug_dump_frames == 0 ) {
3972 Debug_dump_frames = 15;
3973 Debug_dump_trigger = 0;
3974 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3975 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3978 Debug_dump_frames = 0;
3979 Debug_dump_trigger = 0;
3980 gr_dump_frame_stop();
3981 dc_printf( "Frame dumping is now OFF\n" );
3987 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3991 if ( Debug_dump_frames == 0 ) {
3993 Debug_dump_frames = 15;
3994 Debug_dump_trigger = 1;
3995 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3996 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3999 Debug_dump_frames = 0;
4000 Debug_dump_trigger = 0;
4001 gr_dump_frame_stop();
4002 dc_printf( "Frame dumping is now OFF\n" );
4008 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
4012 if ( Debug_dump_frames == 0 ) {
4014 Debug_dump_frames = 30;
4015 Debug_dump_trigger = 0;
4016 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4017 dc_printf( "Frame dumping at 30 hz is now ON\n" );
4020 Debug_dump_frames = 0;
4021 Debug_dump_trigger = 0;
4022 gr_dump_frame_stop();
4023 dc_printf( "Frame dumping is now OFF\n" );
4029 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
4033 if ( Debug_dump_frames == 0 ) {
4035 Debug_dump_frames = 30;
4036 Debug_dump_trigger = 1;
4037 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4038 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
4041 Debug_dump_frames = 0;
4042 Debug_dump_trigger = 0;
4043 gr_dump_frame_stop();
4044 dc_printf( "Triggered frame dumping is now OFF\n" );
4050 void game_maybe_dump_frame()
4052 if ( !Debug_dump_frames ){
4056 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
4063 Debug_dump_frame_num++;
4069 extern int Player_dead_state;
4071 // Flip the page and time how long it took.
4072 void game_flip_page_and_time_it()
4077 t1 = timer_get_fixed_seconds();
4079 t2 = timer_get_fixed_seconds();
4082 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
4083 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
4090 void game_simulation_frame()
4092 // blow ships up in multiplayer dogfight
4093 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){
4094 // blow up all non-player ships
4095 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
4098 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
4100 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)){
4101 moveup = GET_NEXT(moveup);
4104 shipp = &Ships[Objects[moveup->objnum].instance];
4105 sip = &Ship_info[shipp->ship_info_index];
4107 // only blow up small ships
4108 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
4109 // function to simply explode a ship where it is currently at
4110 ship_self_destruct( &Objects[moveup->objnum] );
4113 moveup = GET_NEXT(moveup);
4119 // process AWACS stuff - do this first thing
4122 // single player, set Player hits_this_frame to 0
4123 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
4124 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
4125 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
4129 supernova_process();
4130 if(supernova_active() >= 5){
4134 // fire targeting lasers now so that
4135 // 1 - created this frame
4136 // 2 - collide this frame
4137 // 3 - render this frame
4138 // 4 - ignored and deleted next frame
4139 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
4141 ship_process_targeting_lasers();
4143 // do this here so that it works for multiplayer
4145 // get viewer direction
4146 int viewer_direction = PHYSICS_VIEWER_REAR;
4148 if(Viewer_mode == 0){
4149 viewer_direction = PHYSICS_VIEWER_FRONT;
4151 if(Viewer_mode & VM_PADLOCK_UP){
4152 viewer_direction = PHYSICS_VIEWER_UP;
4154 else if(Viewer_mode & VM_PADLOCK_REAR){
4155 viewer_direction = PHYSICS_VIEWER_REAR;
4157 else if(Viewer_mode & VM_PADLOCK_LEFT){
4158 viewer_direction = PHYSICS_VIEWER_LEFT;
4160 else if(Viewer_mode & VM_PADLOCK_RIGHT){
4161 viewer_direction = PHYSICS_VIEWER_RIGHT;
4164 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
4166 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
4169 #define VM_PADLOCK_UP (1 << 7)
4170 #define VM_PADLOCK_REAR (1 << 8)
4171 #define VM_PADLOCK_LEFT (1 << 9)
4172 #define VM_PADLOCK_RIGHT (1 << 10)
4174 // evaluate mission departures and arrivals before we process all objects.
4175 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
4177 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
4178 // ships/wing packets.
4179 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
4180 mission_parse_eval_stuff();
4183 // if we're an observer, move ourselves seperately from the standard physics
4184 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
4185 obj_observer_move(flFrametime);
4188 // move all the objects now
4189 obj_move_all(flFrametime);
4191 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
4192 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
4193 // ship_check_cargo_all();
4194 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4195 mission_eval_goals();
4199 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
4200 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4201 training_check_objectives();
4204 // do all interpolation now
4205 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
4206 // client side processing of warping in effect stages
4207 multi_do_client_warp(flFrametime);
4209 // client side movement of an observer
4210 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
4211 obj_observer_move(flFrametime);
4214 // move all objects - does interpolation now as well
4215 obj_move_all(flFrametime);
4218 // only process the message queue when the player is "in" the game
4219 if ( !Pre_player_entry ){
4220 message_queue_process(); // process any messages send to the player
4223 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4224 message_maybe_distort(); // maybe distort incoming message if comms damaged
4225 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4226 player_process_pending_praise(); // maybe send off a delayed praise message to the player
4227 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4230 if(!(Game_mode & GM_STANDALONE_SERVER)){
4231 // process some stuff every frame (before frame is rendered)
4232 emp_process_local();
4234 hud_update_frame(); // update hud systems
4236 if (!physics_paused) {
4237 // Move particle system
4238 particle_move_all(flFrametime);
4240 // Move missile trails
4241 trail_move_all(flFrametime);
4243 // process muzzle flashes
4244 mflash_process_all();
4246 // Flash the gun flashes
4247 shipfx_flash_do_frame(flFrametime);
4249 shockwave_move_all(flFrametime); // update all the shockwaves
4252 // subspace missile strikes
4255 obj_snd_do_frame(); // update the object-linked persistant sounds
4256 game_maybe_update_sound_environment();
4257 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4259 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4261 if ( Game_subspace_effect ) {
4262 game_start_subspace_ambient_sound();
4268 // Maybe render and process the dead-popup
4269 void game_maybe_do_dead_popup(float frametime)
4271 if ( popupdead_is_active() ) {
4273 int choice = popupdead_do_frame(frametime);
4275 if ( Game_mode & GM_NORMAL ) {
4279 if(game_do_cd_mission_check(Game_current_mission_filename)){
4280 gameseq_post_event(GS_EVENT_ENTER_GAME);
4282 gameseq_post_event(GS_EVENT_MAIN_MENU);
4287 gameseq_post_event(GS_EVENT_END_GAME);
4292 if(game_do_cd_mission_check(Game_current_mission_filename)){
4293 gameseq_post_event(GS_EVENT_START_GAME);
4295 gameseq_post_event(GS_EVENT_MAIN_MENU);
4299 // this should only happen during a red alert mission
4302 Assert(The_mission.red_alert);
4303 if(!The_mission.red_alert){
4305 if(game_do_cd_mission_check(Game_current_mission_filename)){
4306 gameseq_post_event(GS_EVENT_START_GAME);
4308 gameseq_post_event(GS_EVENT_MAIN_MENU);
4313 // choose the previous mission
4314 mission_campaign_previous_mission();
4316 if(game_do_cd_mission_check(Game_current_mission_filename)){
4317 gameseq_post_event(GS_EVENT_START_GAME);
4319 gameseq_post_event(GS_EVENT_MAIN_MENU);
4330 case POPUPDEAD_DO_MAIN_HALL:
4331 multi_quit_game(PROMPT_NONE,-1);
4334 case POPUPDEAD_DO_RESPAWN:
4335 multi_respawn_normal();
4336 event_music_player_respawn();
4339 case POPUPDEAD_DO_OBSERVER:
4340 multi_respawn_observer();
4341 event_music_player_respawn_as_observer();
4350 if ( leave_popup ) {
4356 // returns true if player is actually in a game_play stats
4357 int game_actually_playing()
4361 state = gameseq_get_state();
4362 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4368 // Draw the 2D HUD gauges
4369 void game_render_hud_2d()
4371 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4375 HUD_render_2d(flFrametime);
4379 // Draw the 3D-dependant HUD gauges
4380 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4382 g3_start_frame(0); // 0 = turn zbuffering off
4383 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4385 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4386 HUD_render_3d(flFrametime);
4390 game_sunspot_process(flFrametime);
4392 // Diminish the palette effect
4393 game_flash_diminish(flFrametime);
4401 int actually_playing;
4402 fix total_time1, total_time2;
4403 fix render2_time1=0, render2_time2=0;
4404 fix render3_time1=0, render3_time2=0;
4405 fix flip_time1=0, flip_time2=0;
4406 fix clear_time1=0, clear_time2=0;
4412 if (Framerate_delay) {
4413 int start_time = timer_get_milliseconds();
4414 while (timer_get_milliseconds() < start_time + Framerate_delay)
4420 demo_do_frame_start();
4422 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4427 // start timing frame
4428 timing_frame_start();
4430 total_time1 = timer_get_fixed_seconds();
4432 // var to hold which state we are in
4433 actually_playing = game_actually_playing();
4435 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4436 if (!(Game_mode & GM_STANDALONE_SERVER)){
4437 Assert( OBJ_INDEX(Player_obj) >= 0 );
4441 if (Missiontime > Entry_delay_time){
4442 Pre_player_entry = 0;
4444 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4447 // Note: These are done even before the player enters, else buffers can overflow.
4448 if (! (Game_mode & GM_STANDALONE_SERVER)){
4452 shield_frame_init();
4454 if ( Player->control_mode != PCM_NORMAL )
4457 if ( !Pre_player_entry && actually_playing ) {
4458 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4460 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4461 game_process_keys();
4463 // don't read flying controls if we're playing a demo back
4464 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4465 read_player_controls( Player_obj, flFrametime);
4469 // if we're not the master, we may have to send the server-critical ship status button_info bits
4470 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4471 multi_maybe_send_ship_status();
4476 // Reset the whack stuff
4479 // These two lines must be outside of Pre_player_entry code,
4480 // otherwise too many lights are added.
4483 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4487 game_simulation_frame();
4489 // if not actually in a game play state, then return. This condition could only be true in
4490 // a multiplayer game.
4491 if ( !actually_playing ) {
4492 Assert( Game_mode & GM_MULTIPLAYER );
4496 if (!Pre_player_entry) {
4497 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4498 clear_time1 = timer_get_fixed_seconds();
4499 // clear the screen to black
4501 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4505 clear_time2 = timer_get_fixed_seconds();
4506 render3_time1 = timer_get_fixed_seconds();
4507 game_render_frame_setup(&eye_pos, &eye_orient);
4508 game_render_frame( &eye_pos, &eye_orient );
4510 // save the eye position and orientation
4511 if ( Game_mode & GM_MULTIPLAYER ) {
4512 Net_player->s_info.eye_pos = eye_pos;
4513 Net_player->s_info.eye_orient = eye_orient;
4516 hud_show_target_model();
4518 // check to see if we should display the death died popup
4519 if(Game_mode & GM_DEAD_BLEW_UP){
4520 if(Game_mode & GM_MULTIPLAYER){
4521 // catch the situation where we're supposed to be warping out on this transition
4522 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4523 gameseq_post_event(GS_EVENT_DEBRIEF);
4524 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4525 Player_died_popup_wait = -1;
4529 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4530 Player_died_popup_wait = -1;
4536 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4537 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4538 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4539 if(!popupdead_is_active()){
4543 Player_multi_died_check = -1;
4547 render3_time2 = timer_get_fixed_seconds();
4548 render2_time1 = timer_get_fixed_seconds();
4551 game_get_framerate();
4552 game_show_framerate();
4554 game_show_time_left();
4556 // Draw the 2D HUD gauges
4557 if(supernova_active() < 3){
4558 game_render_hud_2d();
4561 game_set_view_clip();
4563 // Draw 3D HUD gauges
4564 game_render_hud_3d(&eye_pos, &eye_orient);
4568 render2_time2 = timer_get_fixed_seconds();
4570 // maybe render and process the dead popup
4571 game_maybe_do_dead_popup(flFrametime);
4573 // start timing frame
4574 timing_frame_stop();
4575 // timing_display(30, 10);
4577 // If a regular popup is active, don't flip (popup code flips)
4578 if( !popup_running_state() ){
4579 flip_time1 = timer_get_fixed_seconds();
4580 game_flip_page_and_time_it();
4581 flip_time2 = timer_get_fixed_seconds();
4585 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4588 game_show_standalone_framerate();
4592 game_do_training_checks();
4595 // process lightning (nebula only)
4598 total_time2 = timer_get_fixed_seconds();
4600 // Got some timing numbers
4601 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4602 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4603 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4604 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4605 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4608 demo_do_frame_end();
4610 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4616 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4617 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4618 // died. This resulted in screwed up death sequences.
4620 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4621 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4622 static int timer_paused=0;
4623 #if defined(TIMER_TEST) && !defined(NDEBUG)
4624 static int stop_count,start_count;
4625 static int time_stopped,time_started;
4627 int saved_timestamp_ticker = -1;
4629 void game_reset_time()
4631 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4635 // Last_time = timer_get_fixed_seconds();
4641 void game_stop_time()
4643 if (timer_paused==0) {
4645 time = timer_get_fixed_seconds();
4646 // Save how much time progressed so far in the frame so we can
4647 // use it when we unpause.
4648 Last_delta_time = time - Last_time;
4650 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4651 if (Last_delta_time < 0) {
4652 #if defined(TIMER_TEST) && !defined(NDEBUG)
4653 Int3(); //get Matt!!!!
4655 Last_delta_time = 0;
4657 #if defined(TIMER_TEST) && !defined(NDEBUG)
4658 time_stopped = time;
4661 // Stop the timer_tick stuff...
4662 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4663 saved_timestamp_ticker = timestamp_ticker;
4667 #if defined(TIMER_TEST) && !defined(NDEBUG)
4672 void game_start_time()
4675 Assert(timer_paused >= 0);
4676 if (timer_paused==0) {
4678 time = timer_get_fixed_seconds();
4679 #if defined(TIMER_TEST) && !defined(NDEBUG)
4681 Int3(); //get Matt!!!!
4684 // Take current time, and set it backwards to account for time
4685 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4686 // will be correct when it goes to calculate the frametime next
4688 Last_time = time - Last_delta_time;
4689 #if defined(TIMER_TEST) && !defined(NDEBUG)
4690 time_started = time;
4693 // Restore the timer_tick stuff...
4694 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4695 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4696 timestamp_ticker = saved_timestamp_ticker;
4697 saved_timestamp_ticker = -1;
4700 #if defined(TIMER_TEST) && !defined(NDEBUG)
4706 void game_set_frametime(int state)
4709 float frame_cap_diff;
4711 thistime = timer_get_fixed_seconds();
4713 if ( Last_time == 0 )
4714 Frametime = F1_0 / 30;
4716 Frametime = thistime - Last_time;
4718 // Frametime = F1_0 / 30;
4720 fix debug_frametime = Frametime; // Just used to display frametime.
4722 // If player hasn't entered mission yet, make frame take 1/4 second.
4723 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4726 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4728 fix frame_speed = F1_0 / Debug_dump_frames;
4730 if (Frametime > frame_speed ){
4731 nprintf(("warning","slow frame: %x\n",Frametime));
4734 thistime = timer_get_fixed_seconds();
4735 Frametime = thistime - Last_time;
4736 } while (Frametime < frame_speed );
4738 Frametime = frame_speed;
4742 Assert( Framerate_cap > 0 );
4744 // Cap the framerate so it doesn't get too high.
4748 cap = F1_0/Framerate_cap;
4749 if (Frametime < cap) {
4750 thistime = cap - Frametime;
4751 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4752 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4754 thistime = timer_get_fixed_seconds();
4758 if((Game_mode & GM_STANDALONE_SERVER) &&
4759 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4761 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4762 Sleep((DWORD)(frame_cap_diff*1000));
4764 thistime += fl2f((frame_cap_diff));
4766 Frametime = thistime - Last_time;
4769 // If framerate is too low, cap it.
4770 if (Frametime > MAX_FRAMETIME) {
4772 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4774 // to remove warnings in release build
4775 debug_frametime = fl2f(flFrametime);
4777 Frametime = MAX_FRAMETIME;
4780 Frametime = fixmul(Frametime, Game_time_compression);
4782 Last_time = thistime;
4783 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4785 flFrametime = f2fl(Frametime);
4786 //if(!(Game_mode & GM_PLAYING_DEMO)){
4787 timestamp_inc(flFrametime);
4789 /* if ((Framecount > 0) && (Framecount < 10)) {
4790 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4795 // This is called from game_do_frame(), and from navmap_do_frame()
4796 void game_update_missiontime()
4798 // TODO JAS: Put in if and move this into game_set_frametime,
4799 // fix navmap to call game_stop/start_time
4800 //if ( !timer_paused )
4801 Missiontime += Frametime;
4804 void game_do_frame()
4806 game_set_frametime(GS_STATE_GAME_PLAY);
4807 game_update_missiontime();
4809 if (Game_mode & GM_STANDALONE_SERVER) {
4810 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4813 if ( game_single_step && (last_single_step == game_single_step) ) {
4814 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4815 while( key_checkch() == 0 )
4817 os_set_title( XSTR( "FreeSpace", 171) );
4818 Last_time = timer_get_fixed_seconds();
4821 last_single_step = game_single_step;
4823 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4824 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4828 Keep_mouse_centered = 0;
4829 monitor_update(); // Update monitor variables
4832 void multi_maybe_do_frame()
4834 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4839 int Joymouse_button_status = 0;
4841 // Flush all input devices
4849 Joymouse_button_status = 0;
4851 //mprintf(("Game flush!\n" ));
4854 // function for multiplayer only which calls game_do_state_common() when running the
4856 void game_do_dc_networking()
4858 Assert( Game_mode & GM_MULTIPLAYER );
4860 game_do_state_common( gameseq_get_state() );
4863 // Call this whenever in a loop, or when you need to check for a keystroke.
4864 int game_check_key()
4870 // convert keypad enter to normal enter
4871 if ((k & KEY_MASK) == KEY_PADENTER)
4872 k = (k & ~KEY_MASK) | KEY_ENTER;
4877 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4879 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4880 static int Demo_show_trailer_timestamp = 0;
4882 void demo_reset_trailer_timer()
4884 Demo_show_trailer_timestamp = timer_get_milliseconds();
4887 void demo_maybe_show_trailer(int k)
4890 // if key pressed, reset demo trailer timer
4892 demo_reset_trailer_timer();
4896 // if mouse moved, reset demo trailer timer
4899 mouse_get_delta(&dx, &dy);
4900 if ( (dx > 0) || (dy > 0) ) {
4901 demo_reset_trailer_timer();
4905 // if joystick has moved, reset demo trailer timer
4908 joy_get_delta(&dx, &dy);
4909 if ( (dx > 0) || (dy > 0) ) {
4910 demo_reset_trailer_timer();
4914 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4915 // the low-level code. Ugly, I know... but was the simplest and most
4918 // if 30 seconds since last demo trailer time reset, launch movie
4919 if ( os_foreground() ) {
4920 int now = timer_get_milliseconds();
4921 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4922 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4924 movie_play( NOX("fstrailer2.mve") );
4925 demo_reset_trailer_timer();
4933 // same as game_check_key(), except this is used while actually in the game. Since there
4934 // generally are differences between game control keys and general UI keys, makes sense to
4935 // have seperate functions for each case. If you are not checking a game control while in a
4936 // mission, you should probably be using game_check_key() instead.
4941 if (!os_foreground()) {
4946 // If we're in a single player game, pause it.
4947 if (!(Game_mode & GM_MULTIPLAYER)){
4948 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4949 game_process_pause_key();
4956 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4957 demo_maybe_show_trailer(k);
4960 // Move the mouse cursor with the joystick.
4961 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4962 // Move the mouse cursor with the joystick
4966 joy_get_pos( &jx, &jy, &jz, &jr );
4968 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4969 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4972 mouse_get_real_pos( &mx, &my );
4973 mouse_set_pos( mx+dx, my+dy );
4978 m = mouse_down(MOUSE_LEFT_BUTTON);
4980 if ( j != Joymouse_button_status ) {
4981 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4982 Joymouse_button_status = j;
4984 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4985 } else if ( (!j) && (m) ) {
4986 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4991 // if we should be ignoring keys because of some multiplayer situations
4992 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4996 // If a popup is running, don't process all the Fn keys
4997 if( popup_active() ) {
5001 state = gameseq_get_state();
5003 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
5006 case KEY_DEBUGGED + KEY_BACKSP:
5011 launch_context_help();
5016 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
5018 // don't allow f2 while warping out in multiplayer
5019 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
5024 case GS_STATE_INITIAL_PLAYER_SELECT:
5025 case GS_STATE_OPTIONS_MENU:
5026 case GS_STATE_HUD_CONFIG:
5027 case GS_STATE_CONTROL_CONFIG:
5028 case GS_STATE_DEATH_DIED:
5029 case GS_STATE_DEATH_BLEW_UP:
5030 case GS_STATE_VIEW_MEDALS:
5034 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
5041 // hotkey selection screen -- only valid from briefing and beyond.
5043 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
5044 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) ) {
5045 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
5051 case KEY_DEBUGGED + KEY_F3:
5052 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
5055 case KEY_DEBUGGED + KEY_F4:
5056 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
5060 if(Game_mode & GM_MULTIPLAYER){
5061 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
5062 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5066 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
5067 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5073 case KEY_ESC | KEY_SHIFTED:
5074 // make sure to quit properly out of multiplayer
5075 if(Game_mode & GM_MULTIPLAYER){
5076 multi_quit_game(PROMPT_NONE);
5079 gameseq_post_event( GS_EVENT_QUIT_GAME );
5084 case KEY_DEBUGGED + KEY_P:
5087 case KEY_PRINT_SCRN:
5089 static int counter = 0;
5094 sprintf( tmp_name, NOX("screen%02d"), counter );
5096 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
5097 gr_print_screen(tmp_name);
5105 case KEY_SHIFTED | KEY_ENTER: {
5107 #if !defined(NDEBUG)
5109 if ( Game_mode & GM_NORMAL ){
5113 // if we're in multiplayer mode, do some special networking
5114 if(Game_mode & GM_MULTIPLAYER){
5115 debug_console(game_do_dc_networking);
5122 if ( Game_mode & GM_NORMAL )
5136 gameseq_post_event(GS_EVENT_QUIT_GAME);
5139 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
5142 void camera_set_position( vector *pos )
5147 void camera_set_orient( matrix *orient )
5149 Camera_orient = *orient;
5152 void camera_set_velocity( vector *vel, int instantaneous )
5154 Camera_desired_velocity.xyz.x = 0.0f;
5155 Camera_desired_velocity.xyz.y = 0.0f;
5156 Camera_desired_velocity.xyz.z = 0.0f;
5158 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
5159 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
5160 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
5162 if ( instantaneous ) {
5163 Camera_velocity = Camera_desired_velocity;
5171 vector new_vel, delta_pos;
5173 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
5174 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
5175 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
5177 Camera_velocity = new_vel;
5179 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
5181 vm_vec_add2( &Camera_pos, &delta_pos );
5183 float ot = Camera_time+0.0f;
5185 Camera_time += flFrametime;
5187 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
5190 tmp.xyz.z = 4.739f; // always go this fast forward.
5192 // pick x and y velocities so they are always on a
5193 // circle with a 25 m radius.
5195 float tmp_angle = frand()*PI2;
5197 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
5198 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
5200 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
5202 //mprintf(( "Changing velocity!\n" ));
5203 camera_set_velocity( &tmp, 0 );
5206 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
5207 vector tmp = { 0.0f, 0.0f, 0.0f };
5208 camera_set_velocity( &tmp, 0 );
5213 void end_demo_campaign_do()
5215 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5216 // show upsell screens
5217 demo_upsell_show_screens();
5218 #elif defined(OEM_BUILD)
5219 // show oem upsell screens
5220 oem_upsell_show_screens();
5223 // drop into main hall
5224 gameseq_post_event( GS_EVENT_MAIN_MENU );
5227 // All code to process events. This is the only place
5228 // that you should change the state of the game.
5229 void game_process_event( int current_state, int event )
5231 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5234 case GS_EVENT_SIMULATOR_ROOM:
5235 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5238 case GS_EVENT_MAIN_MENU:
5239 gameseq_set_state(GS_STATE_MAIN_MENU);
5242 case GS_EVENT_OPTIONS_MENU:
5243 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5246 case GS_EVENT_BARRACKS_MENU:
5247 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5250 case GS_EVENT_TECH_MENU:
5251 gameseq_set_state(GS_STATE_TECH_MENU);
5254 case GS_EVENT_TRAINING_MENU:
5255 gameseq_set_state(GS_STATE_TRAINING_MENU);
5258 case GS_EVENT_START_GAME:
5259 Select_default_ship = 0;
5260 Player_multi_died_check = -1;
5261 gameseq_set_state(GS_STATE_CMD_BRIEF);
5264 case GS_EVENT_START_BRIEFING:
5265 gameseq_set_state(GS_STATE_BRIEFING);
5268 case GS_EVENT_DEBRIEF:
5269 // did we end the campaign in the main freespace 2 single player campaign?
5271 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace")) {
5273 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5275 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5277 gameseq_set_state(GS_STATE_DEBRIEF);
5280 Player_multi_died_check = -1;
5283 case GS_EVENT_SHIP_SELECTION:
5284 gameseq_set_state( GS_STATE_SHIP_SELECT );
5287 case GS_EVENT_WEAPON_SELECTION:
5288 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5291 case GS_EVENT_ENTER_GAME:
5293 // maybe start recording a demo
5295 demo_start_record("test.fsd");
5299 if (Game_mode & GM_MULTIPLAYER) {
5300 // if we're respawning, make sure we change the view mode so that the hud shows up
5301 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5305 gameseq_set_state(GS_STATE_GAME_PLAY);
5307 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5310 Player_multi_died_check = -1;
5312 // clear multiplayer button info
5313 extern button_info Multi_ship_status_bi;
5314 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5316 Start_time = f2fl(timer_get_approx_seconds());
5318 mprintf(("Entering game at time = %7.3f\n", Start_time));
5322 case GS_EVENT_START_GAME_QUICK:
5323 Select_default_ship = 1;
5324 gameseq_post_event(GS_EVENT_ENTER_GAME);
5328 case GS_EVENT_END_GAME:
5329 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5330 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5331 gameseq_set_state(GS_STATE_MAIN_MENU);
5336 Player_multi_died_check = -1;
5339 case GS_EVENT_QUIT_GAME:
5340 main_hall_stop_music();
5341 main_hall_stop_ambient();
5342 gameseq_set_state(GS_STATE_QUIT_GAME);
5344 Player_multi_died_check = -1;
5347 case GS_EVENT_GAMEPLAY_HELP:
5348 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5351 case GS_EVENT_PAUSE_GAME:
5352 gameseq_push_state(GS_STATE_GAME_PAUSED);
5355 case GS_EVENT_DEBUG_PAUSE_GAME:
5356 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5359 case GS_EVENT_TRAINING_PAUSE:
5360 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5363 case GS_EVENT_PREVIOUS_STATE:
5364 gameseq_pop_state();
5367 case GS_EVENT_TOGGLE_FULLSCREEN:
5368 #ifndef HARDWARE_ONLY
5370 if ( gr_screen.mode == GR_SOFTWARE ) {
5371 gr_init( GR_640, GR_DIRECTDRAW );
5372 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5373 gr_init( GR_640, GR_SOFTWARE );
5379 case GS_EVENT_TOGGLE_GLIDE:
5381 if ( gr_screen.mode != GR_GLIDE ) {
5382 gr_init( GR_640, GR_GLIDE );
5384 gr_init( GR_640, GR_SOFTWARE );
5389 case GS_EVENT_LOAD_MISSION_MENU:
5390 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5393 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5394 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5397 case GS_EVENT_HUD_CONFIG:
5398 gameseq_push_state( GS_STATE_HUD_CONFIG );
5401 case GS_EVENT_CONTROL_CONFIG:
5402 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5405 case GS_EVENT_DEATH_DIED:
5406 gameseq_set_state( GS_STATE_DEATH_DIED );
5409 case GS_EVENT_DEATH_BLEW_UP:
5410 if ( current_state == GS_STATE_DEATH_DIED ) {
5411 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5412 event_music_player_death();
5414 // multiplayer clients set their extra check here
5415 if(Game_mode & GM_MULTIPLAYER){
5416 // set the multi died absolute last chance check
5417 Player_multi_died_check = time(NULL);
5420 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5424 case GS_EVENT_NEW_CAMPAIGN:
5425 if (!mission_load_up_campaign()){
5426 readyroom_continue_campaign();
5429 Player_multi_died_check = -1;
5432 case GS_EVENT_CAMPAIGN_CHEAT:
5433 if (!mission_load_up_campaign()){
5435 // bash campaign value
5436 extern char Main_hall_campaign_cheat[512];
5439 // look for the mission
5440 for(idx=0; idx<Campaign.num_missions; idx++){
5441 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5442 Campaign.next_mission = idx;
5443 Campaign.prev_mission = idx - 1;
5450 readyroom_continue_campaign();
5453 Player_multi_died_check = -1;
5456 case GS_EVENT_CAMPAIGN_ROOM:
5457 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5460 case GS_EVENT_CMD_BRIEF:
5461 gameseq_set_state(GS_STATE_CMD_BRIEF);
5464 case GS_EVENT_RED_ALERT:
5465 gameseq_set_state(GS_STATE_RED_ALERT);
5468 case GS_EVENT_CREDITS:
5469 gameseq_set_state( GS_STATE_CREDITS );
5472 case GS_EVENT_VIEW_MEDALS:
5473 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5476 case GS_EVENT_SHOW_GOALS:
5477 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5480 case GS_EVENT_HOTKEY_SCREEN:
5481 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5484 // multiplayer stuff follow these comments
5486 case GS_EVENT_MULTI_JOIN_GAME:
5487 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5490 case GS_EVENT_MULTI_HOST_SETUP:
5491 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5494 case GS_EVENT_MULTI_CLIENT_SETUP:
5495 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5498 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5499 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5502 case GS_EVENT_MULTI_STD_WAIT:
5503 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5506 case GS_EVENT_STANDALONE_MAIN:
5507 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5510 case GS_EVENT_MULTI_PAUSE:
5511 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5514 case GS_EVENT_INGAME_PRE_JOIN:
5515 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5518 case GS_EVENT_EVENT_DEBUG:
5519 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5522 // Start a warpout where player automatically goes 70 no matter what
5523 // and can't cancel out of it.
5524 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5525 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5527 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5528 Player->saved_viewer_mode = Viewer_mode;
5529 Player->control_mode = PCM_WARPOUT_STAGE1;
5530 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5531 Warpout_time = 0.0f; // Start timer!
5534 case GS_EVENT_PLAYER_WARPOUT_START:
5535 if ( Player->control_mode != PCM_NORMAL ) {
5536 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5538 Player->saved_viewer_mode = Viewer_mode;
5539 Player->control_mode = PCM_WARPOUT_STAGE1;
5540 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5541 Warpout_time = 0.0f; // Start timer!
5542 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5546 case GS_EVENT_PLAYER_WARPOUT_STOP:
5547 if ( Player->control_mode != PCM_NORMAL ) {
5548 if ( !Warpout_forced ) { // cannot cancel forced warpout
5549 Player->control_mode = PCM_NORMAL;
5550 Viewer_mode = Player->saved_viewer_mode;
5551 hud_subspace_notify_abort();
5552 mprintf(( "Player put back to normal mode.\n" ));
5553 if ( Warpout_sound > -1 ) {
5554 snd_stop( Warpout_sound );
5561 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5562 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5563 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5564 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5566 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5567 shipfx_warpout_start( Player_obj );
5568 Player->control_mode = PCM_WARPOUT_STAGE2;
5569 Player->saved_viewer_mode = Viewer_mode;
5570 Viewer_mode |= VM_WARP_CHASE;
5572 vector tmp = Player_obj->pos;
5574 ship_get_eye( &tmp, &tmp_m, Player_obj );
5575 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5576 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5577 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5579 camera_set_position( &tmp );
5580 camera_set_orient( &Player_obj->orient );
5581 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5583 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5584 camera_set_velocity( &tmp_vel, 1);
5588 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5589 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5590 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5591 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5593 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5594 Player->control_mode = PCM_WARPOUT_STAGE3;
5598 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5599 mprintf(( "Player warped out. Going to debriefing!\n" ));
5600 Player->control_mode = PCM_NORMAL;
5601 Viewer_mode = Player->saved_viewer_mode;
5604 // we have a special debriefing screen for multiplayer furballs
5605 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5606 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5608 // do the normal debriefing for all other situations
5610 gameseq_post_event(GS_EVENT_DEBRIEF);
5614 case GS_EVENT_STANDALONE_POSTGAME:
5615 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5618 case GS_EVENT_INITIAL_PLAYER_SELECT:
5619 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5622 case GS_EVENT_GAME_INIT:
5623 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5624 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5626 // see if the command line option has been set to use the last pilot, and act acoordingly
5627 if( player_select_get_last_pilot() ) {
5628 // always enter the main menu -- do the automatic network startup stuff elsewhere
5629 // so that we still have valid checks for networking modes, etc.
5630 gameseq_set_state(GS_STATE_MAIN_MENU);
5632 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5637 case GS_EVENT_MULTI_MISSION_SYNC:
5638 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5641 case GS_EVENT_MULTI_START_GAME:
5642 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5645 case GS_EVENT_MULTI_HOST_OPTIONS:
5646 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5649 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5650 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5653 case GS_EVENT_TEAM_SELECT:
5654 gameseq_set_state(GS_STATE_TEAM_SELECT);
5657 case GS_EVENT_END_CAMPAIGN:
5658 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5661 case GS_EVENT_END_DEMO:
5662 gameseq_set_state(GS_STATE_END_DEMO);
5665 case GS_EVENT_LOOP_BRIEF:
5666 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5675 // Called when a state is being left.
5676 // The current state is still at old_state, but as soon as
5677 // this function leaves, then the current state will become
5678 // new state. You should never try to change the state
5679 // in here... if you think you need to, you probably really
5680 // need to post an event, not change the state.
5681 void game_leave_state( int old_state, int new_state )
5683 int end_mission = 1;
5685 switch (new_state) {
5686 case GS_STATE_GAME_PAUSED:
5687 case GS_STATE_DEBUG_PAUSED:
5688 case GS_STATE_OPTIONS_MENU:
5689 case GS_STATE_CONTROL_CONFIG:
5690 case GS_STATE_MISSION_LOG_SCROLLBACK:
5691 case GS_STATE_DEATH_DIED:
5692 case GS_STATE_SHOW_GOALS:
5693 case GS_STATE_HOTKEY_SCREEN:
5694 case GS_STATE_MULTI_PAUSED:
5695 case GS_STATE_TRAINING_PAUSED:
5696 case GS_STATE_EVENT_DEBUG:
5697 case GS_STATE_GAMEPLAY_HELP:
5698 end_mission = 0; // these events shouldn't end a mission
5702 switch (old_state) {
5703 case GS_STATE_BRIEFING:
5704 brief_stop_voices();
5705 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5706 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5707 && (new_state != GS_STATE_TEAM_SELECT) ){
5708 common_select_close();
5709 if ( new_state == GS_STATE_MAIN_MENU ) {
5710 freespace_stop_mission();
5714 // COMMAND LINE OPTION
5715 if (Cmdline_multi_stream_chat_to_file){
5716 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5717 cfclose(Multi_chat_stream);
5721 case GS_STATE_DEBRIEF:
5722 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5727 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5728 multi_df_debrief_close();
5731 case GS_STATE_LOAD_MISSION_MENU:
5732 mission_load_menu_close();
5735 case GS_STATE_SIMULATOR_ROOM:
5739 case GS_STATE_CAMPAIGN_ROOM:
5740 campaign_room_close();
5743 case GS_STATE_CMD_BRIEF:
5744 if (new_state == GS_STATE_OPTIONS_MENU) {
5749 if (new_state == GS_STATE_MAIN_MENU)
5750 freespace_stop_mission();
5755 case GS_STATE_RED_ALERT:
5759 case GS_STATE_SHIP_SELECT:
5760 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5761 new_state != GS_STATE_HOTKEY_SCREEN &&
5762 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5763 common_select_close();
5764 if ( new_state == GS_STATE_MAIN_MENU ) {
5765 freespace_stop_mission();
5770 case GS_STATE_WEAPON_SELECT:
5771 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5772 new_state != GS_STATE_HOTKEY_SCREEN &&
5773 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5774 common_select_close();
5775 if ( new_state == GS_STATE_MAIN_MENU ) {
5776 freespace_stop_mission();
5781 case GS_STATE_TEAM_SELECT:
5782 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5783 new_state != GS_STATE_HOTKEY_SCREEN &&
5784 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5785 common_select_close();
5786 if ( new_state == GS_STATE_MAIN_MENU ) {
5787 freespace_stop_mission();
5792 case GS_STATE_MAIN_MENU:
5793 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5800 case GS_STATE_OPTIONS_MENU:
5801 //game_start_time();
5802 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5803 multi_join_clear_game_list();
5805 options_menu_close();
5808 case GS_STATE_BARRACKS_MENU:
5809 if(new_state != GS_STATE_VIEW_MEDALS){
5814 case GS_STATE_MISSION_LOG_SCROLLBACK:
5815 hud_scrollback_close();
5818 case GS_STATE_TRAINING_MENU:
5819 training_menu_close();
5822 case GS_STATE_GAME_PLAY:
5823 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5824 player_save_target_and_weapon_link_prefs();
5825 game_stop_looped_sounds();
5828 sound_env_disable();
5829 joy_ff_stop_effects();
5831 // stop game time under certain conditions
5832 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5837 // shut down any recording or playing demos
5842 // when in multiplayer and going back to the main menu, send a leave game packet
5843 // right away (before calling stop mission). stop_mission was taking to long to
5844 // close mission down and I want people to get notified ASAP.
5845 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5846 multi_quit_game(PROMPT_NONE);
5849 freespace_stop_mission();
5850 Game_time_compression = F1_0;
5854 case GS_STATE_TECH_MENU:
5858 case GS_STATE_TRAINING_PAUSED:
5859 Training_num_lines = 0;
5860 // fall through to GS_STATE_GAME_PAUSED
5862 case GS_STATE_GAME_PAUSED:
5864 if ( end_mission ) {
5869 case GS_STATE_DEBUG_PAUSED:
5872 pause_debug_close();
5876 case GS_STATE_HUD_CONFIG:
5880 // join/start a game
5881 case GS_STATE_MULTI_JOIN_GAME:
5882 if(new_state != GS_STATE_OPTIONS_MENU){
5883 multi_join_game_close();
5887 case GS_STATE_MULTI_HOST_SETUP:
5888 case GS_STATE_MULTI_CLIENT_SETUP:
5889 // if this is just the host going into the options screen, don't do anything
5890 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5894 // close down the proper state
5895 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5896 multi_create_game_close();
5898 multi_game_client_setup_close();
5901 // COMMAND LINE OPTION
5902 if (Cmdline_multi_stream_chat_to_file){
5903 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5904 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5905 cfclose(Multi_chat_stream);
5910 case GS_STATE_CONTROL_CONFIG:
5911 control_config_close();
5914 case GS_STATE_DEATH_DIED:
5915 Game_mode &= ~GM_DEAD_DIED;
5917 // early end while respawning or blowing up in a multiplayer game
5918 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5920 freespace_stop_mission();
5924 case GS_STATE_DEATH_BLEW_UP:
5925 Game_mode &= ~GM_DEAD_BLEW_UP;
5927 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5928 // to determine if I should do anything.
5929 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5931 freespace_stop_mission();
5934 // if we are not respawing as an observer or as a player, our new state will not
5935 // be gameplay state.
5936 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5937 game_stop_time(); // hasn't been called yet!!
5938 freespace_stop_mission();
5944 case GS_STATE_CREDITS:
5948 case GS_STATE_VIEW_MEDALS:
5952 case GS_STATE_SHOW_GOALS:
5953 mission_show_goals_close();
5956 case GS_STATE_HOTKEY_SCREEN:
5957 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5958 mission_hotkey_close();
5962 case GS_STATE_MULTI_MISSION_SYNC:
5963 // if we're moving into the options menu, don't do anything
5964 if(new_state == GS_STATE_OPTIONS_MENU){
5968 Assert( Game_mode & GM_MULTIPLAYER );
5970 if ( new_state == GS_STATE_GAME_PLAY ){
5971 // palette_restore_palette();
5973 // change a couple of flags to indicate our state!!!
5974 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5975 send_netplayer_update_packet();
5977 // set the game mode
5978 Game_mode |= GM_IN_MISSION;
5982 case GS_STATE_VIEW_CUTSCENES:
5983 cutscenes_screen_close();
5986 case GS_STATE_MULTI_STD_WAIT:
5987 multi_standalone_wait_close();
5990 case GS_STATE_STANDALONE_MAIN:
5991 standalone_main_close();
5992 if(new_state == GS_STATE_MULTI_STD_WAIT){
5993 init_multiplayer_stats();
5997 case GS_STATE_MULTI_PAUSED:
5998 // if ( end_mission ){
6003 case GS_STATE_INGAME_PRE_JOIN:
6004 multi_ingame_select_close();
6007 case GS_STATE_STANDALONE_POSTGAME:
6008 multi_standalone_postgame_close();
6011 case GS_STATE_INITIAL_PLAYER_SELECT:
6012 player_select_close();
6015 case GS_STATE_MULTI_START_GAME:
6016 multi_start_game_close();
6019 case GS_STATE_MULTI_HOST_OPTIONS:
6020 multi_host_options_close();
6023 case GS_STATE_END_OF_CAMPAIGN:
6024 mission_campaign_end_close();
6027 case GS_STATE_LOOP_BRIEF:
6033 // Called when a state is being entered.
6034 // The current state is set to the state we're entering at
6035 // this point, and old_state is set to the state we're coming
6036 // from. You should never try to change the state
6037 // in here... if you think you need to, you probably really
6038 // need to post an event, not change the state.
6040 void game_enter_state( int old_state, int new_state )
6042 switch (new_state) {
6043 case GS_STATE_MAIN_MENU:
6044 // in multiplayer mode, be sure that we are not doing networking anymore.
6045 if ( Game_mode & GM_MULTIPLAYER ) {
6046 Assert( Net_player != NULL );
6047 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
6050 Game_time_compression = F1_0;
6052 // determine which ship this guy is currently based on
6053 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6056 if (Player->on_bastion) {
6064 case GS_STATE_BRIEFING:
6065 main_hall_stop_music();
6066 main_hall_stop_ambient();
6068 if (Game_mode & GM_NORMAL) {
6069 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6070 // MWA: or from options or hotkey screens
6071 // JH: or if the command brief state already did this
6072 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6073 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
6074 && (old_state != GS_STATE_CMD_BRIEF) ) {
6075 if ( !game_start_mission() ) // this should put us into a new state on failure!
6079 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6080 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6081 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6083 Game_time_compression = F1_0;
6085 if ( red_alert_mission() ) {
6086 gameseq_post_event(GS_EVENT_RED_ALERT);
6093 case GS_STATE_DEBRIEF:
6094 game_stop_looped_sounds();
6095 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
6096 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
6101 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6102 multi_df_debrief_init();
6105 case GS_STATE_LOAD_MISSION_MENU:
6106 mission_load_menu_init();
6109 case GS_STATE_SIMULATOR_ROOM:
6113 case GS_STATE_CAMPAIGN_ROOM:
6114 campaign_room_init();
6117 case GS_STATE_RED_ALERT:
6118 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6122 case GS_STATE_CMD_BRIEF: {
6123 int team_num = 0; // team number used as index for which cmd brief to use.
6125 if (old_state == GS_STATE_OPTIONS_MENU) {
6129 main_hall_stop_music();
6130 main_hall_stop_ambient();
6132 if (Game_mode & GM_NORMAL) {
6133 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6134 // MWA: or from options or hotkey screens
6135 // JH: or if the command brief state already did this
6136 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6137 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
6138 if ( !game_start_mission() ) // this should put us into a new state on failure!
6143 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6144 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6145 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6147 cmd_brief_init(team_num);
6153 case GS_STATE_SHIP_SELECT:
6157 case GS_STATE_WEAPON_SELECT:
6158 weapon_select_init();
6161 case GS_STATE_TEAM_SELECT:
6165 case GS_STATE_GAME_PAUSED:
6170 case GS_STATE_DEBUG_PAUSED:
6171 // game_stop_time();
6172 // os_set_title("FreeSpace - PAUSED");
6175 case GS_STATE_TRAINING_PAUSED:
6182 case GS_STATE_OPTIONS_MENU:
6184 options_menu_init();
6187 case GS_STATE_GAME_PLAY:
6188 // coming from the gameplay state or the main menu, we might need to load the mission
6189 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
6190 if ( !game_start_mission() ) // this should put us into a new state.
6195 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
6196 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
6197 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
6198 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
6199 (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) ) {
6200 // JAS: Used to do all paging here.
6204 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
6208 main_hall_stop_music();
6209 main_hall_stop_ambient();
6210 event_music_first_pattern(); // start the first pattern
6213 // special code that restores player ship selection and weapons loadout when doing a quick start
6214 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
6215 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
6216 wss_direct_restore_loadout();
6220 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
6221 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
6222 event_music_first_pattern(); // start the first pattern
6225 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
6226 event_music_first_pattern(); // start the first pattern
6228 player_restore_target_and_weapon_link_prefs();
6230 Game_mode |= GM_IN_MISSION;
6233 // required to truely make mouse deltas zeroed in debug mouse code
6234 void mouse_force_pos(int x, int y);
6235 if (!Is_standalone) {
6236 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6242 // only start time if in single player, or coming from multi wait state
6245 (Game_mode & GM_NORMAL) &&
6246 (old_state != GS_STATE_VIEW_CUTSCENES)
6248 (Game_mode & GM_MULTIPLAYER) && (
6249 (old_state == GS_STATE_MULTI_PAUSED) ||
6250 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6256 // when coming from the multi paused state, reset the timestamps
6257 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6258 multi_reset_timestamps();
6261 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6262 // initialize all object update details
6263 multi_oo_gameplay_init();
6266 // under certain circumstances, the server should reset the object update rate limiting stuff
6267 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6268 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6270 // reinitialize the rate limiting system for all clients
6271 multi_oo_rate_init_all();
6274 // multiplayer clients should always re-initialize their control info rate limiting system
6275 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6276 multi_oo_rate_init_all();
6280 if(Game_mode & GM_MULTIPLAYER){
6281 multi_ping_reset_players();
6284 Game_subspace_effect = 0;
6285 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6286 Game_subspace_effect = 1;
6287 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6288 game_start_subspace_ambient_sound();
6292 sound_env_set(&Game_sound_env);
6293 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6295 // clear multiplayer button info i
6296 extern button_info Multi_ship_status_bi;
6297 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6300 case GS_STATE_HUD_CONFIG:
6304 case GS_STATE_MULTI_JOIN_GAME:
6305 multi_join_clear_game_list();
6307 if (old_state != GS_STATE_OPTIONS_MENU) {
6308 multi_join_game_init();
6313 case GS_STATE_MULTI_HOST_SETUP:
6314 // don't reinitialize if we're coming back from the host options screen
6315 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6316 multi_create_game_init();
6321 case GS_STATE_MULTI_CLIENT_SETUP:
6322 if (old_state != GS_STATE_OPTIONS_MENU) {
6323 multi_game_client_setup_init();
6328 case GS_STATE_CONTROL_CONFIG:
6329 control_config_init();
6332 case GS_STATE_TECH_MENU:
6336 case GS_STATE_BARRACKS_MENU:
6337 if(old_state != GS_STATE_VIEW_MEDALS){
6342 case GS_STATE_MISSION_LOG_SCROLLBACK:
6343 hud_scrollback_init();
6346 case GS_STATE_DEATH_DIED:
6347 Player_died_time = timestamp(10);
6349 if(!(Game_mode & GM_MULTIPLAYER)){
6350 player_show_death_message();
6352 Game_mode |= GM_DEAD_DIED;
6355 case GS_STATE_DEATH_BLEW_UP:
6356 if ( !popupdead_is_active() ) {
6357 Player_ai->target_objnum = -1;
6360 // stop any local EMP effect
6363 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6364 Game_mode |= GM_DEAD_BLEW_UP;
6365 Show_viewing_from_self = 0;
6367 // timestamp how long we should wait before displaying the died popup
6368 if ( !popupdead_is_active() ) {
6369 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6373 case GS_STATE_GAMEPLAY_HELP:
6374 gameplay_help_init();
6377 case GS_STATE_CREDITS:
6378 main_hall_stop_music();
6379 main_hall_stop_ambient();
6383 case GS_STATE_VIEW_MEDALS:
6384 medal_main_init(Player);
6387 case GS_STATE_SHOW_GOALS:
6388 mission_show_goals_init();
6391 case GS_STATE_HOTKEY_SCREEN:
6392 mission_hotkey_init();
6395 case GS_STATE_MULTI_MISSION_SYNC:
6396 // if we're coming from the options screen, don't do any
6397 if(old_state == GS_STATE_OPTIONS_MENU){
6401 switch(Multi_sync_mode){
6402 case MULTI_SYNC_PRE_BRIEFING:
6403 // if moving from game forming to the team select state
6406 case MULTI_SYNC_POST_BRIEFING:
6407 // if moving from briefing into the mission itself
6410 // tell everyone that we're now loading data
6411 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6412 send_netplayer_update_packet();
6414 // JAS: Used to do all paging here!!!!
6416 Net_player->state = NETPLAYER_STATE_WAITING;
6417 send_netplayer_update_packet();
6419 Game_time_compression = F1_0;
6421 case MULTI_SYNC_INGAME:
6427 case GS_STATE_VIEW_CUTSCENES:
6428 cutscenes_screen_init();
6431 case GS_STATE_MULTI_STD_WAIT:
6432 multi_standalone_wait_init();
6435 case GS_STATE_STANDALONE_MAIN:
6436 // don't initialize if we're coming from one of these 2 states unless there are no
6437 // players left (reset situation)
6438 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6439 standalone_main_init();
6443 case GS_STATE_MULTI_PAUSED:
6447 case GS_STATE_INGAME_PRE_JOIN:
6448 multi_ingame_select_init();
6451 case GS_STATE_STANDALONE_POSTGAME:
6452 multi_standalone_postgame_init();
6455 case GS_STATE_INITIAL_PLAYER_SELECT:
6456 player_select_init();
6459 case GS_STATE_MULTI_START_GAME:
6460 multi_start_game_init();
6463 case GS_STATE_MULTI_HOST_OPTIONS:
6464 multi_host_options_init();
6467 case GS_STATE_END_OF_CAMPAIGN:
6468 mission_campaign_end_init();
6471 case GS_STATE_LOOP_BRIEF:
6478 // do stuff that may need to be done regardless of state
6479 void game_do_state_common(int state,int no_networking)
6481 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6482 snd_do_frame(); // update sound system
6483 event_music_do_frame(); // music needs to play across many states
6485 multi_log_process();
6487 if (no_networking) {
6491 // maybe do a multiplayer frame based on game mode and state type
6492 if (Game_mode & GM_MULTIPLAYER) {
6494 case GS_STATE_OPTIONS_MENU:
6495 case GS_STATE_GAMEPLAY_HELP:
6496 case GS_STATE_HOTKEY_SCREEN:
6497 case GS_STATE_HUD_CONFIG:
6498 case GS_STATE_CONTROL_CONFIG:
6499 case GS_STATE_MISSION_LOG_SCROLLBACK:
6500 case GS_STATE_SHOW_GOALS:
6501 case GS_STATE_VIEW_CUTSCENES:
6502 case GS_STATE_EVENT_DEBUG:
6503 multi_maybe_do_frame();
6507 game_do_networking();
6511 // Called once a frame.
6512 // You should never try to change the state
6513 // in here... if you think you need to, you probably really
6514 // need to post an event, not change the state.
6515 int Game_do_state_should_skip = 0;
6516 void game_do_state(int state)
6518 // always lets the do_state_common() function determine if the state should be skipped
6519 Game_do_state_should_skip = 0;
6521 // legal to set the should skip state anywhere in this function
6522 game_do_state_common(state); // do stuff that may need to be done regardless of state
6524 if(Game_do_state_should_skip){
6529 case GS_STATE_MAIN_MENU:
6530 game_set_frametime(GS_STATE_MAIN_MENU);
6531 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6534 main_hall_do(flFrametime);
6538 case GS_STATE_OPTIONS_MENU:
6539 game_set_frametime(GS_STATE_OPTIONS_MENU);
6540 options_menu_do_frame(flFrametime);
6543 case GS_STATE_BARRACKS_MENU:
6544 game_set_frametime(GS_STATE_BARRACKS_MENU);
6545 barracks_do_frame(flFrametime);
6548 case GS_STATE_TRAINING_MENU:
6549 game_set_frametime(GS_STATE_TRAINING_MENU);
6550 training_menu_do_frame(flFrametime);
6553 case GS_STATE_TECH_MENU:
6554 game_set_frametime(GS_STATE_TECH_MENU);
6555 techroom_do_frame(flFrametime);
6558 case GS_STATE_GAMEPLAY_HELP:
6559 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6560 gameplay_help_do_frame(flFrametime);
6563 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6567 case GS_STATE_GAME_PAUSED:
6571 case GS_STATE_DEBUG_PAUSED:
6573 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6578 case GS_STATE_TRAINING_PAUSED:
6579 game_training_pause_do();
6582 case GS_STATE_LOAD_MISSION_MENU:
6583 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6584 mission_load_menu_do();
6587 case GS_STATE_BRIEFING:
6588 game_set_frametime(GS_STATE_BRIEFING);
6589 brief_do_frame(flFrametime);
6592 case GS_STATE_DEBRIEF:
6593 game_set_frametime(GS_STATE_DEBRIEF);
6594 debrief_do_frame(flFrametime);
6597 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6598 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6599 multi_df_debrief_do();
6602 case GS_STATE_SHIP_SELECT:
6603 game_set_frametime(GS_STATE_SHIP_SELECT);
6604 ship_select_do(flFrametime);
6607 case GS_STATE_WEAPON_SELECT:
6608 game_set_frametime(GS_STATE_WEAPON_SELECT);
6609 weapon_select_do(flFrametime);
6612 case GS_STATE_MISSION_LOG_SCROLLBACK:
6613 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6614 hud_scrollback_do_frame(flFrametime);
6617 case GS_STATE_HUD_CONFIG:
6618 game_set_frametime(GS_STATE_HUD_CONFIG);
6619 hud_config_do_frame(flFrametime);
6622 case GS_STATE_MULTI_JOIN_GAME:
6623 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6624 multi_join_game_do_frame();
6627 case GS_STATE_MULTI_HOST_SETUP:
6628 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6629 multi_create_game_do();
6632 case GS_STATE_MULTI_CLIENT_SETUP:
6633 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6634 multi_game_client_setup_do_frame();
6637 case GS_STATE_CONTROL_CONFIG:
6638 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6639 control_config_do_frame(flFrametime);
6642 case GS_STATE_DEATH_DIED:
6646 case GS_STATE_DEATH_BLEW_UP:
6650 case GS_STATE_SIMULATOR_ROOM:
6651 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6652 sim_room_do_frame(flFrametime);
6655 case GS_STATE_CAMPAIGN_ROOM:
6656 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6657 campaign_room_do_frame(flFrametime);
6660 case GS_STATE_RED_ALERT:
6661 game_set_frametime(GS_STATE_RED_ALERT);
6662 red_alert_do_frame(flFrametime);
6665 case GS_STATE_CMD_BRIEF:
6666 game_set_frametime(GS_STATE_CMD_BRIEF);
6667 cmd_brief_do_frame(flFrametime);
6670 case GS_STATE_CREDITS:
6671 game_set_frametime(GS_STATE_CREDITS);
6672 credits_do_frame(flFrametime);
6675 case GS_STATE_VIEW_MEDALS:
6676 game_set_frametime(GS_STATE_VIEW_MEDALS);
6680 case GS_STATE_SHOW_GOALS:
6681 game_set_frametime(GS_STATE_SHOW_GOALS);
6682 mission_show_goals_do_frame(flFrametime);
6685 case GS_STATE_HOTKEY_SCREEN:
6686 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6687 mission_hotkey_do_frame(flFrametime);
6690 case GS_STATE_VIEW_CUTSCENES:
6691 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6692 cutscenes_screen_do_frame();
6695 case GS_STATE_MULTI_STD_WAIT:
6696 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6697 multi_standalone_wait_do();
6700 case GS_STATE_STANDALONE_MAIN:
6701 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6702 standalone_main_do();
6705 case GS_STATE_MULTI_PAUSED:
6706 game_set_frametime(GS_STATE_MULTI_PAUSED);
6710 case GS_STATE_TEAM_SELECT:
6711 game_set_frametime(GS_STATE_TEAM_SELECT);
6715 case GS_STATE_INGAME_PRE_JOIN:
6716 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6717 multi_ingame_select_do();
6720 case GS_STATE_EVENT_DEBUG:
6722 game_set_frametime(GS_STATE_EVENT_DEBUG);
6723 game_show_event_debug(flFrametime);
6727 case GS_STATE_STANDALONE_POSTGAME:
6728 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6729 multi_standalone_postgame_do();
6732 case GS_STATE_INITIAL_PLAYER_SELECT:
6733 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6737 case GS_STATE_MULTI_MISSION_SYNC:
6738 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6742 case GS_STATE_MULTI_START_GAME:
6743 game_set_frametime(GS_STATE_MULTI_START_GAME);
6744 multi_start_game_do();
6747 case GS_STATE_MULTI_HOST_OPTIONS:
6748 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6749 multi_host_options_do();
6752 case GS_STATE_END_OF_CAMPAIGN:
6753 mission_campaign_end_do();
6756 case GS_STATE_END_DEMO:
6757 game_set_frametime(GS_STATE_END_DEMO);
6758 end_demo_campaign_do();
6761 case GS_STATE_LOOP_BRIEF:
6762 game_set_frametime(GS_STATE_LOOP_BRIEF);
6766 } // end switch(gs_current_state)
6770 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6771 int game_do_ram_check(int ram_in_bytes)
6773 if ( ram_in_bytes < 30*1024*1024 ) {
6774 int allowed_to_run = 1;
6775 if ( ram_in_bytes < 25*1024*1024 ) {
6780 int Freespace_total_ram_MB;
6781 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6783 if ( allowed_to_run ) {
6785 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);
6790 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6791 if ( msgbox_rval == IDCANCEL ) {
6798 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);
6800 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6811 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6812 // If so, copy it over and remove the update directory.
6813 void game_maybe_update_launcher(char *exe_dir)
6816 char src_filename[MAX_PATH];
6817 char dest_filename[MAX_PATH];
6819 strcpy(src_filename, exe_dir);
6820 strcat(src_filename, NOX("\\update\\freespace.exe"));
6822 strcpy(dest_filename, exe_dir);
6823 strcat(dest_filename, NOX("\\freespace.exe"));
6825 // see if src_filename exists
6827 fp = fopen(src_filename, "rb");
6833 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6835 // copy updated freespace.exe to freespace exe dir
6836 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6837 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 );
6841 // delete the file in the update directory
6842 DeleteFile(src_filename);
6844 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6845 char update_dir[MAX_PATH];
6846 strcpy(update_dir, exe_dir);
6847 strcat(update_dir, NOX("\\update"));
6848 RemoveDirectory(update_dir);
6854 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6858 int sub_total_destroyed = 0;
6862 // get the total for all his children
6863 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6864 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6867 // find the # of faces for this _individual_ object
6868 total = submodel_get_num_polys(model_num, sm);
6869 if(strstr(pm->submodel[sm].name, "-destroyed")){
6870 sub_total_destroyed = total;
6874 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6877 *out_total += total + sub_total;
6878 *out_destroyed_total += sub_total_destroyed;
6881 #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);
6882 void game_spew_pof_info()
6884 char *pof_list[1000];
6887 int idx, model_num, i, j;
6889 int total, root_total, model_total, destroyed_total, counted;
6893 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6895 // spew info on all the pofs
6901 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6906 for(idx=0; idx<num_files; idx++, counted++){
6907 sprintf(str, "%s.pof", pof_list[idx]);
6908 model_num = model_load(str, 0, NULL);
6910 pm = model_get(model_num);
6912 // if we have a real model
6917 // go through and print all raw submodels
6918 cfputs("RAW\n", out);
6921 for (i=0; i<pm->n_models; i++) {
6922 total = submodel_get_num_polys(model_num, i);
6924 model_total += total;
6925 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6928 sprintf(str, "Model total %d\n", model_total);
6931 // now go through and do it by LOD
6932 cfputs("BY LOD\n\n", out);
6933 for(i=0; i<pm->n_detail_levels; i++){
6934 sprintf(str, "LOD %d\n", i);
6938 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6940 destroyed_total = 0;
6941 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6942 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6945 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6948 sprintf(str, "TOTAL: %d\n", total + root_total);
6950 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6952 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6955 cfputs("------------------------------------------------------------------------\n\n", out);
6959 if(counted >= MAX_POLYGON_MODELS - 5){
6972 game_spew_pof_info();
6975 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6980 // Don't let more than one instance of Freespace run.
6981 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6983 SetForegroundWindow(hwnd);
6988 // Find out how much RAM is on this machine
6991 ms.dwLength = sizeof(MEMORYSTATUS);
6992 GlobalMemoryStatus(&ms);
6993 Freespace_total_ram = ms.dwTotalPhys;
6995 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6999 if ( ms.dwTotalVirtual < 1024 ) {
7000 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
7004 if (!vm_init(24*1024*1024)) {
7005 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 );
7009 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
7011 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);
7019 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
7020 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
7021 seem worth bothering with.
7025 lResult = RegOpenKeyEx(
7026 HKEY_LOCAL_MACHINE, // Where it is
7027 "Software\\Microsoft\\DirectX", // name of key
7028 NULL, // DWORD reserved
7029 KEY_QUERY_VALUE, // Allows all changes
7030 &hKey // Location to store key
7033 if (lResult == ERROR_SUCCESS) {
7035 DWORD dwType, dwLen;
7038 lResult = RegQueryValueEx(
7039 hKey, // Handle to key
7040 "Version", // The values name
7041 NULL, // DWORD reserved
7042 &dwType, // What kind it is
7043 (ubyte *) version, // value to set
7044 &dwLen // How many bytes to set
7047 if (lResult == ERROR_SUCCESS) {
7048 dx_version = atoi(strstr(version, ".") + 1);
7052 DWORD dwType, dwLen;
7055 lResult = RegQueryValueEx(
7056 hKey, // Handle to key
7057 "InstalledVersion", // The values name
7058 NULL, // DWORD reserved
7059 &dwType, // What kind it is
7060 (ubyte *) &val, // value to set
7061 &dwLen // How many bytes to set
7064 if (lResult == ERROR_SUCCESS) {
7072 if (dx_version < 3) {
7073 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
7074 "latest version of DirectX at:\n\n"
7075 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
7077 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
7078 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
7083 //=====================================================
7084 // Make sure we're running in the right directory.
7088 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
7089 char *p = exe_dir + strlen(exe_dir);
7091 // chop off the filename
7092 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
7098 if ( strlen(exe_dir) > 0 ) {
7099 SetCurrentDirectory(exe_dir);
7102 // check for updated freespace.exe
7103 game_maybe_update_launcher(exe_dir);
7111 extern void windebug_memwatch_init();
7112 windebug_memwatch_init();
7116 parse_cmdline(szCmdLine);
7118 #ifdef STANDALONE_ONLY_BUILD
7120 nprintf(("Network", "Standalone running"));
7123 nprintf(("Network", "Standalone running"));
7131 // maybe spew pof stuff
7132 if(Cmdline_spew_pof_info){
7133 game_spew_pof_info();
7138 // non-demo, non-standalone, play the intro movie
7144 // to avoid crashes on debug build
7145 for (i=0; i<5; i++) {
7149 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) ){
7151 #if defined(OEM_BUILD)
7152 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
7154 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
7155 #endif // defined(OEM_BUILD)
7158 for (int i=0; i<5; i++) {
7159 if (plist[i] != NULL) {
7164 #endif // RELEASE_REAL
7167 if ( !Is_standalone ) {
7169 // release -- movies always play
7172 // 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
7173 movie_play( NOX("intro.mve"), 0 );
7175 // debug version, movie will only play with -showmovies
7176 #elif !defined(NDEBUG)
7178 movie_play( NOX("intro.mve"), 0);
7181 if ( Cmdline_show_movies )
7182 movie_play( NOX("intro.mve"), 0 );
7191 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
7193 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
7197 // only important for non THREADED mode
7200 state = gameseq_process_events();
7201 if ( state == GS_STATE_QUIT_GAME ){
7206 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7208 demo_upsell_show_screens();
7210 #elif defined(OEM_BUILD)
7211 // show upsell screens on exit
7212 oem_upsell_show_screens();
7219 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7225 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7227 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
7229 // Do nothing here - RecordExceptionInfo() has already done
7230 // everything that is needed. Actually this code won't even
7231 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
7232 // the __except clause.
7236 nprintf(("WinMain", "exceptions shall fall through"));
7238 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7244 // launcher the fslauncher program on exit
7245 void game_launch_launcher_on_exit()
7249 PROCESS_INFORMATION pi;
7250 char cmd_line[2048];
7251 char original_path[1024] = "";
7253 memset( &si, 0, sizeof(STARTUPINFO) );
7257 _getcwd(original_path, 1023);
7259 // set up command line
7260 strcpy(cmd_line, original_path);
7261 strcat(cmd_line, "\\");
7262 strcat(cmd_line, LAUNCHER_FNAME);
7263 strcat(cmd_line, " -straight_to_update");
7265 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7266 cmd_line, // pointer to command line string
7267 NULL, // pointer to process security attributes
7268 NULL, // pointer to thread security attributes
7269 FALSE, // handle inheritance flag
7270 CREATE_DEFAULT_ERROR_MODE, // creation flags
7271 NULL, // pointer to new environment block
7272 NULL, // pointer to current directory name
7273 &si, // pointer to STARTUPINFO
7274 &pi // pointer to PROCESS_INFORMATION
7276 // to eliminate build warnings
7286 // This function is called when FreeSpace terminates normally.
7288 void game_shutdown(void)
7294 // don't ever flip a page on the standalone!
7295 if(!(Game_mode & GM_STANDALONE_SERVER)){
7301 // if the player has left the "player select" screen and quit the game without actually choosing
7302 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7303 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7307 // load up common multiplayer icons
7308 multi_unload_common_icons();
7310 shockwave_close(); // release any memory used by shockwave system
7311 fireball_close(); // free fireball system
7312 ship_close(); // free any memory that was allocated for the ships
7313 weapon_close(); // free any memory that was allocated for the weapons
7314 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7315 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7316 bm_unload_all(); // free bitmaps
7317 mission_campaign_close(); // close out the campaign stuff
7318 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
7319 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7321 #ifdef MULTI_USE_LAG
7325 // the menu close functions will unload the bitmaps if they were displayed during the game
7326 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7329 context_help_close(); // close out help system
7330 training_menu_close();
7331 lcl_close(); // be sure localization is closed out
7334 // free left-over memory from parsed tables
7335 cutscene_tbl_close();
7337 scoring_tbl_close();
7339 extern void joy_close();
7342 audiostream_close();
7344 event_music_close();
7348 // HACKITY HACK HACK
7349 // if this flag is set, we should be firing up the launcher when exiting freespace
7350 extern int Multi_update_fireup_launcher_on_exit;
7351 if(Multi_update_fireup_launcher_on_exit){
7352 game_launch_launcher_on_exit();
7356 // game_stop_looped_sounds()
7358 // This function will call the appropriate stop looped sound functions for those
7359 // modules which use looping sounds. It is not enough just to stop a looping sound
7360 // at the DirectSound level, the game is keeping track of looping sounds, and this
7361 // function is used to inform the game that looping sounds are being halted.
7363 void game_stop_looped_sounds()
7365 hud_stop_looped_locking_sounds();
7366 hud_stop_looped_engine_sounds();
7367 afterburner_stop_sounds();
7368 player_stop_looped_sounds();
7369 obj_snd_stop_all(); // stop all object-linked persistant sounds
7370 game_stop_subspace_ambient_sound();
7371 snd_stop(Radar_static_looping);
7372 Radar_static_looping = -1;
7373 snd_stop(Target_static_looping);
7374 shipfx_stop_engine_wash_sound();
7375 Target_static_looping = -1;
7378 //////////////////////////////////////////////////////////////////////////
7380 // Code for supporting an animating mouse pointer
7383 //////////////////////////////////////////////////////////////////////////
7385 typedef struct animating_obj
7394 static animating_obj Animating_mouse;
7396 // ----------------------------------------------------------------------------
7397 // init_animating_pointer()
7399 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7400 // gets properly initialized
7402 void init_animating_pointer()
7404 Animating_mouse.first_frame = -1;
7405 Animating_mouse.num_frames = 0;
7406 Animating_mouse.current_frame = -1;
7407 Animating_mouse.time = 0.0f;
7408 Animating_mouse.elapsed_time = 0.0f;
7411 // ----------------------------------------------------------------------------
7412 // load_animating_pointer()
7414 // Called at game init to load in the frames for the animating mouse pointer
7416 // input: filename => filename of animation file that holds the animation
7418 void load_animating_pointer(char *filename, int dx, int dy)
7423 init_animating_pointer();
7425 am = &Animating_mouse;
7426 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7427 if ( am->first_frame == -1 )
7428 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7429 am->current_frame = 0;
7430 am->time = am->num_frames / i2fl(fps);
7433 // ----------------------------------------------------------------------------
7434 // unload_animating_pointer()
7436 // Called at game shutdown to free the memory used to store the animation frames
7438 void unload_animating_pointer()
7443 am = &Animating_mouse;
7444 for ( i = 0; i < am->num_frames; i++ ) {
7445 Assert( (am->first_frame+i) >= 0 );
7446 bm_release(am->first_frame + i);
7449 am->first_frame = -1;
7451 am->current_frame = -1;
7454 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7455 void game_render_mouse(float frametime)
7460 // if animating cursor exists, play the next frame
7461 am = &Animating_mouse;
7462 if ( am->first_frame != -1 ) {
7463 mouse_get_pos(&mx, &my);
7464 am->elapsed_time += frametime;
7465 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7466 if ( am->current_frame >= am->num_frames ) {
7467 am->current_frame = 0;
7468 am->elapsed_time = 0.0f;
7470 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7474 // ----------------------------------------------------------------------------
7475 // game_maybe_draw_mouse()
7477 // determines whether to draw the mouse pointer at all, and what frame of
7478 // animation to use if the mouse is animating
7480 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7482 // input: frametime => elapsed frame time in seconds since last call
7484 void game_maybe_draw_mouse(float frametime)
7488 game_state = gameseq_get_state();
7490 switch ( game_state ) {
7491 case GS_STATE_GAME_PAUSED:
7492 // case GS_STATE_MULTI_PAUSED:
7493 case GS_STATE_GAME_PLAY:
7494 case GS_STATE_DEATH_DIED:
7495 case GS_STATE_DEATH_BLEW_UP:
7496 if ( popup_active() || popupdead_is_active() ) {
7508 if ( !Mouse_hidden )
7509 game_render_mouse(frametime);
7513 void game_do_training_checks()
7517 waypoint_list *wplp;
7519 if (Training_context & TRAINING_CONTEXT_SPEED) {
7520 s = (int) Player_obj->phys_info.fspeed;
7521 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7522 if (!Training_context_speed_set) {
7523 Training_context_speed_set = 1;
7524 Training_context_speed_timestamp = timestamp();
7528 Training_context_speed_set = 0;
7531 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7532 wplp = &Waypoint_lists[Training_context_path];
7533 if (wplp->count > Training_context_goal_waypoint) {
7534 i = Training_context_goal_waypoint;
7536 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7537 if (d <= Training_context_distance) {
7538 Training_context_at_waypoint = i;
7539 if (Training_context_goal_waypoint == i) {
7540 Training_context_goal_waypoint++;
7541 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7548 if (i == wplp->count)
7551 } while (i != Training_context_goal_waypoint);
7555 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7556 Players_target = Player_ai->target_objnum;
7557 Players_targeted_subsys = Player_ai->targeted_subsys;
7558 Players_target_timestamp = timestamp();
7562 /////////// Following is for event debug view screen
7566 #define EVENT_DEBUG_MAX 5000
7567 #define EVENT_DEBUG_EVENT 0x8000
7569 int Event_debug_index[EVENT_DEBUG_MAX];
7572 void game_add_event_debug_index(int n, int indent)
7574 if (ED_count < EVENT_DEBUG_MAX)
7575 Event_debug_index[ED_count++] = n | (indent << 16);
7578 void game_add_event_debug_sexp(int n, int indent)
7583 if (Sexp_nodes[n].first >= 0) {
7584 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7585 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7589 game_add_event_debug_index(n, indent);
7590 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7591 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7593 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7596 void game_event_debug_init()
7601 for (e=0; e<Num_mission_events; e++) {
7602 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7603 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7607 void game_show_event_debug(float frametime)
7611 int font_height, font_width;
7613 static int scroll_offset = 0;
7615 k = game_check_key();
7621 if (scroll_offset < 0)
7631 scroll_offset -= 20;
7632 if (scroll_offset < 0)
7637 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7641 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7647 gr_set_color_fast(&Color_bright);
7649 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7651 gr_set_color_fast(&Color_normal);
7653 gr_get_string_size(&font_width, &font_height, NOX("test"));
7654 y_max = gr_screen.max_h - font_height - 5;
7658 while (k < ED_count) {
7659 if (y_index > y_max)
7662 z = Event_debug_index[k];
7663 if (z & EVENT_DEBUG_EVENT) {
7665 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7666 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7667 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7668 Mission_events[z].repeat_count, Mission_events[z].interval);
7676 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7677 switch (Sexp_nodes[z & 0x7fff].value) {
7679 strcat(buf, NOX(" (True)"));
7683 strcat(buf, NOX(" (False)"));
7686 case SEXP_KNOWN_TRUE:
7687 strcat(buf, NOX(" (Always true)"));
7690 case SEXP_KNOWN_FALSE:
7691 strcat(buf, NOX(" (Always false)"));
7694 case SEXP_CANT_EVAL:
7695 strcat(buf, NOX(" (Can't eval)"));
7699 case SEXP_NAN_FOREVER:
7700 strcat(buf, NOX(" (Not a number)"));
7705 gr_printf(10, y_index, buf);
7706 y_index += font_height;
7719 extern int Tmap_npixels;
7721 int Tmap_num_too_big = 0;
7722 int Num_models_needing_splitting = 0;
7724 void Time_model( int modelnum )
7726 // mprintf(( "Timing ship '%s'\n", si->name ));
7728 vector eye_pos, model_pos;
7729 matrix eye_orient, model_orient;
7731 polymodel *pm = model_get( modelnum );
7733 int l = strlen(pm->filename);
7735 if ( (l == '/') || (l=='\\') || (l==':')) {
7741 char *pof_file = &pm->filename[l];
7743 int model_needs_splitting = 0;
7745 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7747 for (i=0; i<pm->n_textures; i++ ) {
7748 char filename[1024];
7751 int bmp_num = pm->original_textures[i];
7752 if ( bmp_num > -1 ) {
7753 bm_get_palette(pm->original_textures[i], pal, filename );
7755 bm_get_info( pm->original_textures[i],&w, &h );
7758 if ( (w > 512) || (h > 512) ) {
7759 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7761 model_needs_splitting++;
7764 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7768 if ( model_needs_splitting ) {
7769 Num_models_needing_splitting++;
7771 eye_orient = model_orient = vmd_identity_matrix;
7772 eye_pos = model_pos = vmd_zero_vector;
7774 eye_pos.xyz.z = -pm->rad*2.0f;
7776 vector eye_to_model;
7778 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7779 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7781 fix t1 = timer_get_fixed_seconds();
7784 ta.p = ta.b = ta.h = 0.0f;
7789 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7791 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7793 modelstats_num_polys = modelstats_num_verts = 0;
7795 while( ta.h < PI2 ) {
7798 vm_angles_2_matrix(&m1, &ta );
7799 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7806 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7808 model_clear_instance( modelnum );
7809 model_set_detail_level(0); // use highest detail level
7810 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7818 int k = key_inkey();
7819 if ( k == KEY_ESC ) {
7824 fix t2 = timer_get_fixed_seconds();
7826 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7827 //bitmaps_used_this_frame /= framecount;
7829 modelstats_num_polys /= framecount;
7830 modelstats_num_verts /= framecount;
7832 Tmap_npixels /=framecount;
7835 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7836 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 );
7837 // 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 );
7843 int Time_models = 0;
7844 DCF_BOOL( time_models, Time_models );
7846 void Do_model_timings_test()
7850 if ( !Time_models ) return;
7852 mprintf(( "Timing models!\n" ));
7856 ubyte model_used[MAX_POLYGON_MODELS];
7857 int model_id[MAX_POLYGON_MODELS];
7858 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7863 for (i=0; i<Num_ship_types; i++ ) {
7864 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7866 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7867 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7870 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7871 if ( !Texture_fp ) return;
7873 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7874 if ( !Time_fp ) return;
7876 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7877 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7879 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7880 if ( model_used[i] ) {
7881 Time_model( model_id[i] );
7885 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7886 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7895 // Call this function when you want to inform the player that a feature is not
7896 // enabled in the DEMO version of FreSpace
7897 void game_feature_not_in_demo_popup()
7899 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7902 // format the specified time (fixed point) into a nice string
7903 void game_format_time(fix m_time,char *time_str)
7906 int hours,minutes,seconds;
7909 mtime = f2fl(m_time);
7911 // get the hours, minutes and seconds
7912 hours = (int)(mtime / 3600.0f);
7914 mtime -= (3600.0f * (float)hours);
7916 seconds = (int)mtime%60;
7917 minutes = (int)mtime/60;
7919 // print the hour if necessary
7921 sprintf(time_str,XSTR( "%d:", 201),hours);
7922 // if there are less than 10 minutes, print a leading 0
7924 strcpy(tmp,NOX("0"));
7925 strcat(time_str,tmp);
7929 // print the minutes
7931 sprintf(tmp,XSTR( "%d:", 201),minutes);
7932 strcat(time_str,tmp);
7934 sprintf(time_str,XSTR( "%d:", 201),minutes);
7937 // print the seconds
7939 strcpy(tmp,NOX("0"));
7940 strcat(time_str,tmp);
7942 sprintf(tmp,"%d",seconds);
7943 strcat(time_str,tmp);
7946 // Stuff version string in *str.
7947 void get_version_string(char *str)
7950 if ( FS_VERSION_BUILD == 0 ) {
7951 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7953 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7956 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7958 #elif defined (OEM_BUILD)
7959 strcat(str, " (OEM)");
7965 char myname[_MAX_PATH];
7966 int namelen, major, minor, build, waste;
7967 unsigned int buf_size;
7973 // Find my EXE file name
7974 hMod = GetModuleHandle(NULL);
7975 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7977 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7978 infop = (char *)malloc(version_size);
7979 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7981 // get the product version
7982 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7983 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7985 sprintf(str,"Dv%d.%02d",major, minor);
7987 sprintf(str,"v%d.%02d",major, minor);
7992 void get_version_string_short(char *str)
7994 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7997 // ----------------------------------------------------------------
7999 // OEM UPSELL SCREENS BEGIN
8001 // ----------------------------------------------------------------
8002 #if defined(OEM_BUILD)
8004 #define NUM_OEM_UPSELL_SCREENS 3
8005 #define OEM_UPSELL_SCREEN_DELAY 10000
8007 static int Oem_upsell_bitmaps_loaded = 0;
8008 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
8009 static int Oem_upsell_screen_number = 0;
8010 static int Oem_upsell_show_next_bitmap_time;
8013 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
8026 static int Oem_normal_cursor = -1;
8027 static int Oem_web_cursor = -1;
8028 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
8029 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
8031 void oem_upsell_next_screen()
8033 Oem_upsell_screen_number++;
8034 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
8035 // extra long delay, mouse shown on last upsell
8036 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
8040 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8044 void oem_upsell_load_bitmaps()
8048 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8049 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
8053 void oem_upsell_unload_bitmaps()
8057 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8058 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
8059 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
8064 Oem_upsell_bitmaps_loaded = 0;
8067 // clickable hotspot on 3rd OEM upsell screen
8068 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
8070 28, 350, 287, 96 // x, y, w, h
8073 45, 561, 460, 152 // x, y, w, h
8077 void oem_upsell_show_screens()
8079 int current_time, k;
8082 if ( !Oem_upsell_bitmaps_loaded ) {
8083 oem_upsell_load_bitmaps();
8084 Oem_upsell_bitmaps_loaded = 1;
8087 // may use upsell screens more than once
8088 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8089 Oem_upsell_screen_number = 0;
8095 int nframes; // used to pass, not really needed (should be 1)
8096 Oem_normal_cursor = gr_get_cursor_bitmap();
8097 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
8098 Assert(Oem_web_cursor >= 0);
8099 if (Oem_web_cursor < 0) {
8100 Oem_web_cursor = Oem_normal_cursor;
8105 //oem_reset_trailer_timer();
8107 current_time = timer_get_milliseconds();
8112 // advance screen on keypress or timeout
8113 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
8114 oem_upsell_next_screen();
8117 // check if we are done
8118 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
8119 Oem_upsell_screen_number--;
8122 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
8127 // show me the upsell
8128 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
8129 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
8133 // if this is the 3rd upsell, make it clickable, d00d
8134 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
8136 int button_state = mouse_get_pos(&mx, &my);
8137 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])
8138 && (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]) )
8141 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
8144 if (button_state & MOUSE_LEFT_BUTTON) {
8146 multi_pxo_url(OEM_UPSELL_URL);
8150 // switch cursor back to normal one
8151 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8156 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8166 oem_upsell_unload_bitmaps();
8168 // switch cursor back to normal one
8169 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8173 #endif // defined(OEM_BUILD)
8174 // ----------------------------------------------------------------
8176 // OEM UPSELL SCREENS END
8178 // ----------------------------------------------------------------
8182 // ----------------------------------------------------------------
8184 // DEMO UPSELL SCREENS BEGIN
8186 // ----------------------------------------------------------------
8188 #if defined(FS2_DEMO) || defined(FS1_DEMO)
8191 #define NUM_DEMO_UPSELL_SCREENS 2
8193 #define NUM_DEMO_UPSELL_SCREENS 4
8195 #define DEMO_UPSELL_SCREEN_DELAY 3000
8197 static int Demo_upsell_bitmaps_loaded = 0;
8198 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
8199 static int Demo_upsell_screen_number = 0;
8200 static int Demo_upsell_show_next_bitmap_time;
8203 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
8229 void demo_upsell_next_screen()
8231 Demo_upsell_screen_number++;
8232 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
8233 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
8235 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8239 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
8240 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8241 #ifndef HARDWARE_ONLY
8242 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8249 void demo_upsell_load_bitmaps()
8253 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8254 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
8258 void demo_upsell_unload_bitmaps()
8262 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8263 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8264 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8269 Demo_upsell_bitmaps_loaded = 0;
8272 void demo_upsell_show_screens()
8274 int current_time, k;
8277 if ( !Demo_upsell_bitmaps_loaded ) {
8278 demo_upsell_load_bitmaps();
8279 Demo_upsell_bitmaps_loaded = 1;
8282 // may use upsell screens more than once
8283 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8284 Demo_upsell_screen_number = 0;
8291 demo_reset_trailer_timer();
8293 current_time = timer_get_milliseconds();
8300 // don't time out, wait for keypress
8302 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8303 demo_upsell_next_screen();
8308 demo_upsell_next_screen();
8311 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8312 Demo_upsell_screen_number--;
8315 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8320 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8321 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8326 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8336 demo_upsell_unload_bitmaps();
8341 // ----------------------------------------------------------------
8343 // DEMO UPSELL SCREENS END
8345 // ----------------------------------------------------------------
8348 // ----------------------------------------------------------------
8350 // Subspace Ambient Sound START
8352 // ----------------------------------------------------------------
8354 static int Subspace_ambient_left_channel = -1;
8355 static int Subspace_ambient_right_channel = -1;
8358 void game_start_subspace_ambient_sound()
8360 if ( Subspace_ambient_left_channel < 0 ) {
8361 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8364 if ( Subspace_ambient_right_channel < 0 ) {
8365 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8369 void game_stop_subspace_ambient_sound()
8371 if ( Subspace_ambient_left_channel >= 0 ) {
8372 snd_stop(Subspace_ambient_left_channel);
8373 Subspace_ambient_left_channel = -1;
8376 if ( Subspace_ambient_right_channel >= 0 ) {
8377 snd_stop(Subspace_ambient_right_channel);
8378 Subspace_ambient_right_channel = -1;
8382 // ----------------------------------------------------------------
8384 // Subspace Ambient Sound END
8386 // ----------------------------------------------------------------
8388 // ----------------------------------------------------------------
8390 // CDROM detection code START
8392 // ----------------------------------------------------------------
8394 #define CD_SIZE_72_MINUTE_MAX (697000000)
8396 uint game_get_cd_used_space(char *path)
8400 char use_path[512] = "";
8401 char sub_path[512] = "";
8402 WIN32_FIND_DATA find;
8405 // recurse through all files and directories
8406 strcpy(use_path, path);
8407 strcat(use_path, "*.*");
8408 find_handle = FindFirstFile(use_path, &find);
8411 if(find_handle == INVALID_HANDLE_VALUE){
8417 // subdirectory. make sure to ignore . and ..
8418 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8420 strcpy(sub_path, path);
8421 strcat(sub_path, find.cFileName);
8422 strcat(sub_path, "\\");
8423 total += game_get_cd_used_space(sub_path);
8425 total += (uint)find.nFileSizeLow;
8427 } while(FindNextFile(find_handle, &find));
8430 FindClose(find_handle);
8442 // if volume_name is non-null, the CD name must match that
8443 int find_freespace_cd(char *volume_name)
8446 char oldpath[MAX_PATH];
8450 int volume_match = 0;
8454 GetCurrentDirectory(MAX_PATH, oldpath);
8456 for (i = 0; i < 26; i++)
8462 path[0] = (char)('A'+i);
8463 if (GetDriveType(path) == DRIVE_CDROM) {
8465 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8466 nprintf(("CD", "CD volume: %s\n", volume));
8468 // check for any CD volume
8469 int volume1_present = 0;
8470 int volume2_present = 0;
8471 int volume3_present = 0;
8473 char full_check[512] = "";
8475 // look for setup.exe
8476 strcpy(full_check, path);
8477 strcat(full_check, "setup.exe");
8478 find_handle = _findfirst(full_check, &find);
8479 if(find_handle != -1){
8480 volume1_present = 1;
8481 _findclose(find_handle);
8484 // look for intro.mve
8485 strcpy(full_check, path);
8486 strcat(full_check, "intro.mve");
8487 find_handle = _findfirst(full_check, &find);
8488 if(find_handle != -1){
8489 volume2_present = 1;
8490 _findclose(find_handle);
8493 // look for endpart1.mve
8494 strcpy(full_check, path);
8495 strcat(full_check, "endpart1.mve");
8496 find_handle = _findfirst(full_check, &find);
8497 if(find_handle != -1){
8498 volume3_present = 1;
8499 _findclose(find_handle);
8502 // see if we have the specific CD we're looking for
8503 if ( volume_name ) {
8505 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8509 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8513 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8517 if ( volume1_present || volume2_present || volume3_present ) {
8522 // 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
8523 if ( volume_match ){
8525 // 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
8526 if(volume2_present || volume3_present) {
8527 // first step - check to make sure its a cdrom
8528 if(GetDriveType(path) != DRIVE_CDROM){
8532 #if !defined(OEM_BUILD)
8533 // oem not on 80 min cds, so dont check tha size
8535 uint used_space = game_get_cd_used_space(path);
8536 if(used_space < CD_SIZE_72_MINUTE_MAX){
8539 #endif // !defined(OEM_BUILD)
8547 #endif // RELEASE_REAL
8553 SetCurrentDirectory(oldpath);
8562 int set_cdrom_path(int drive_num)
8566 if (drive_num < 0) { //no CD
8568 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8571 strcpy(Game_CDROM_dir,""); //set directory
8575 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8591 i = find_freespace_cd();
8593 rval = set_cdrom_path(i);
8597 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8599 nprintf(("CD", "FreeSpace CD not found\n"));
8607 int Last_cd_label_found = 0;
8608 char Last_cd_label[256];
8610 int game_cd_changed()
8617 if ( strlen(Game_CDROM_dir) == 0 ) {
8621 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8623 if ( found != Last_cd_label_found ) {
8624 Last_cd_label_found = found;
8626 mprintf(( "CD '%s' was inserted\n", label ));
8629 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8633 if ( Last_cd_label_found ) {
8634 if ( !stricmp( Last_cd_label, label )) {
8635 //mprintf(( "CD didn't change\n" ));
8637 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8641 // none found before, none found now.
8642 //mprintf(( "still no CD...\n" ));
8646 Last_cd_label_found = found;
8648 strcpy( Last_cd_label, label );
8650 strcpy( Last_cd_label, "" );
8661 // check if _any_ FreeSpace2 CDs are in the drive
8662 // return: 1 => CD now in drive
8663 // 0 => Could not find CD, they refuse to put it in the drive
8664 int game_do_cd_check(char *volume_name)
8666 #if !defined(GAME_CD_CHECK)
8672 int num_attempts = 0;
8673 int refresh_files = 0;
8675 int path_set_ok, popup_rval;
8677 cd_drive_num = find_freespace_cd(volume_name);
8678 path_set_ok = set_cdrom_path(cd_drive_num);
8679 if ( path_set_ok ) {
8681 if ( refresh_files ) {
8693 // no CD found, so prompt user
8694 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8696 if ( popup_rval != 1 ) {
8701 if ( num_attempts++ > 5 ) {
8712 // check if _any_ FreeSpace2 CDs are in the drive
8713 // return: 1 => CD now in drive
8714 // 0 => Could not find CD, they refuse to put it in the drive
8715 int game_do_cd_check_specific(char *volume_name, int cdnum)
8720 int num_attempts = 0;
8721 int refresh_files = 0;
8723 int path_set_ok, popup_rval;
8725 cd_drive_num = find_freespace_cd(volume_name);
8726 path_set_ok = set_cdrom_path(cd_drive_num);
8727 if ( path_set_ok ) {
8729 if ( refresh_files ) {
8740 // no CD found, so prompt user
8741 #if defined(DVD_MESSAGE_HACK)
8742 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8744 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8747 if ( popup_rval != 1 ) {
8752 if ( num_attempts++ > 5 ) {
8762 // only need to do this in RELEASE_REAL
8763 int game_do_cd_mission_check(char *filename)
8769 fs_builtin_mission *m = game_find_builtin_mission(filename);
8771 // check for changed CD
8772 if(game_cd_changed()){
8777 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8781 // not builtin, so do a general check (any FS2 CD will do)
8783 return game_do_cd_check();
8786 // does not have any CD requirement, do a general check
8787 if(strlen(m->cd_volume) <= 0){
8788 return game_do_cd_check();
8792 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8794 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8797 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8801 return game_do_cd_check();
8804 // did we find the cd?
8805 if(find_freespace_cd(m->cd_volume) >= 0){
8809 // make sure the volume exists
8810 int num_attempts = 0;
8811 int refresh_files = 0;
8813 int path_set_ok, popup_rval;
8815 cd_drive_num = find_freespace_cd(m->cd_volume);
8816 path_set_ok = set_cdrom_path(cd_drive_num);
8817 if ( path_set_ok ) {
8819 if ( refresh_files ) {
8826 // no CD found, so prompt user
8827 #if defined(DVD_MESSAGE_HACK)
8828 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8830 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8834 if ( popup_rval != 1 ) {
8839 if ( num_attempts++ > 5 ) {
8851 // ----------------------------------------------------------------
8853 // CDROM detection code END
8855 // ----------------------------------------------------------------
8857 // ----------------------------------------------------------------
8859 // Language Autodetection stuff
8862 // this layout order must match Lcl_languages in localize.cpp in order for the
8863 // correct language to be detected
8864 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
8866 1366105450, // English
8868 589986744, // English
8870 -1132430286, // German
8872 -1131728960, // Polish
8875 // default setting is "-1" to use config file with English as fall back
8876 // DO NOT change the default setting here or something uncouth might happen
8877 // in the localization code
8883 // try and open the file to verify
8884 CFILE *detect = cfopen("font01.vf", "rb");
8886 // will use default setting if something went wrong
8891 // get the long checksum of the file
8893 cfseek(detect, 0, SEEK_SET);
8894 cf_chksum_long(detect, &file_checksum);
8898 // now compare the checksum/filesize against known #'s
8899 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8900 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8905 // notify if a match was not found, include detected checksum
8906 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8907 printf("Using default language...\n\n");
8913 // End Auto Lang stuff
8915 // ----------------------------------------------------------------
8917 // ----------------------------------------------------------------
8918 // SHIPS TBL VERIFICATION STUFF
8921 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8922 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8923 #define NUM_SHIPS_TBL_CHECKSUMS 3
8925 #define NUM_SHIPS_TBL_CHECKSUMS 1
8929 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8930 1696074201, // FS2 demo
8933 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8934 1603375034, // FS1 DEMO
8937 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8938 -129679197, // FS1 Full 1.06 (US)
8939 7762567, // FS1 SilentThreat
8940 1555372475 // FS1 Full 1.06 (German)
8944 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8945 -463907578, // US - beta 1
8946 1696074201, // FS2 demo
8949 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8950 // -1022810006, // 1.0 FULL
8951 -1254285366 // 1.2 FULL (German)
8955 void verify_ships_tbl()
8959 Game_ships_tbl_valid = 1;
8965 // detect if the packfile exists
8966 CFILE *detect = cfopen("ships.tbl", "rb");
8967 Game_ships_tbl_valid = 0;
8971 Game_ships_tbl_valid = 0;
8975 // get the long checksum of the file
8977 cfseek(detect, 0, SEEK_SET);
8978 cf_chksum_long(detect, &file_checksum);
8982 // now compare the checksum/filesize against known #'s
8983 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8984 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8985 Game_ships_tbl_valid = 1;
8992 DCF(shipspew, "display the checksum for the current ships.tbl")
8995 CFILE *detect = cfopen("ships.tbl", "rb");
8996 // get the long checksum of the file
8998 cfseek(detect, 0, SEEK_SET);
8999 cf_chksum_long(detect, &file_checksum);
9002 dc_printf("%d", file_checksum);
9005 // ----------------------------------------------------------------
9006 // WEAPONS TBL VERIFICATION STUFF
9009 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
9010 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
9011 #define NUM_WEAPONS_TBL_CHECKSUMS 3
9013 #define NUM_WEAPONS_TBL_CHECKSUMS 1
9017 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9018 -266420030, // demo 1
9021 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9022 -1246928725, // FS1 DEMO
9025 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9026 -834598107, // FS1 1.06 Full (US)
9027 -1652231417, // FS1 SilentThreat
9028 720209793 // FS1 1.06 Full (German)
9032 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9033 141718090, // US - beta 1
9034 -266420030, // demo 1
9037 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9038 // 399297860, // 1.0 FULL
9039 -553984927 // 1.2 FULL (german)
9043 void verify_weapons_tbl()
9047 Game_weapons_tbl_valid = 1;
9053 // detect if the packfile exists
9054 CFILE *detect = cfopen("weapons.tbl", "rb");
9055 Game_weapons_tbl_valid = 0;
9059 Game_weapons_tbl_valid = 0;
9063 // get the long checksum of the file
9065 cfseek(detect, 0, SEEK_SET);
9066 cf_chksum_long(detect, &file_checksum);
9070 // now compare the checksum/filesize against known #'s
9071 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
9072 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
9073 Game_weapons_tbl_valid = 1;
9080 DCF(wepspew, "display the checksum for the current weapons.tbl")
9083 CFILE *detect = cfopen("weapons.tbl", "rb");
9084 // get the long checksum of the file
9086 cfseek(detect, 0, SEEK_SET);
9087 cf_chksum_long(detect, &file_checksum);
9090 dc_printf("%d", file_checksum);
9093 // if the game is running using hacked data
9094 int game_hacked_data()
9097 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
9105 void display_title_screen()
9107 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
9108 ///int title_bitmap;
9111 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
9112 if (title_bitmap == -1) {
9118 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9119 extern void d3d_start_frame();
9125 gr_set_bitmap(title_bitmap);
9132 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9133 extern void d3d_stop_frame();
9141 bm_unload(title_bitmap);
9142 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
9145 // return true if the game is running with "low memory", which is less than 48MB
9146 bool game_using_low_mem()
9148 if (Use_low_mem == 0) {