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.32 2003/06/19 11:51:41 taylor
19 * adjustments to memory leak fixes
21 * Revision 1.31 2003/06/11 18:30:32 taylor
24 * Revision 1.30 2003/06/03 04:00:39 taylor
25 * Polish language support (Janusz Dziemidowicz)
27 * Revision 1.29 2003/05/25 02:30:42 taylor
30 * Revision 1.28 2003/05/18 03:55:30 taylor
31 * automatic language selection support
33 * Revision 1.27 2003/03/03 04:54:44 theoddone33
34 * Commit Taylor's ShowFPS fix
36 * Revision 1.26 2003/02/20 17:41:07 theoddone33
37 * Userdir patch from Taylor Richards
39 * Revision 1.25 2003/01/30 19:54:10 relnev
40 * ini config option for the frames per second counter (Taylor Richards)
42 * Revision 1.24 2002/08/31 01:39:13 theoddone33
43 * Speed up the renderer a tad
45 * Revision 1.23 2002/08/04 02:31:00 relnev
46 * make numlock not overlap with pause
48 * Revision 1.22 2002/08/02 23:07:03 relnev
49 * don't access the mouse in standalone mode
51 * Revision 1.21 2002/07/28 05:05:08 relnev
52 * removed some old stuff
54 * Revision 1.20 2002/07/24 00:20:41 relnev
57 * Revision 1.19 2002/06/17 06:33:08 relnev
58 * ryan's struct patch for gcc 2.95
60 * Revision 1.18 2002/06/16 04:46:33 relnev
61 * set up correct checksums for demo
63 * Revision 1.17 2002/06/09 04:41:17 relnev
64 * added copyright header
66 * Revision 1.16 2002/06/09 03:16:04 relnev
69 * removed unneeded asm, old sdl 2d setup.
71 * fixed crash caused by opengl_get_region.
73 * Revision 1.15 2002/06/05 08:05:28 relnev
74 * stub/warning removal.
76 * reworked the sound code.
78 * Revision 1.14 2002/06/05 04:03:32 relnev
79 * finished cfilesystem.
81 * removed some old code.
83 * fixed mouse save off-by-one.
87 * Revision 1.13 2002/06/02 04:26:34 relnev
90 * Revision 1.12 2002/06/02 00:31:35 relnev
91 * implemented osregistry
93 * Revision 1.11 2002/06/01 09:00:34 relnev
94 * silly debug memmanager
96 * Revision 1.10 2002/06/01 07:12:32 relnev
97 * a few NDEBUG updates.
99 * removed a few warnings.
101 * Revision 1.9 2002/05/31 03:05:59 relnev
104 * Revision 1.8 2002/05/29 02:52:32 theoddone33
105 * Enable OpenGL renderer
107 * Revision 1.7 2002/05/28 08:52:03 relnev
108 * implemented two assembly stubs.
110 * cleaned up a few warnings.
112 * added a little demo hackery to make it progress a little farther.
114 * Revision 1.6 2002/05/28 06:28:20 theoddone33
115 * Filesystem mods, actually reads some data files now
117 * Revision 1.5 2002/05/28 04:07:28 theoddone33
118 * New graphics stubbing arrangement
120 * Revision 1.4 2002/05/27 22:46:52 theoddone33
121 * Remove more undefined symbols
123 * Revision 1.3 2002/05/26 23:31:18 relnev
124 * added a few files that needed to be compiled
126 * freespace.cpp: now compiles
128 * Revision 1.2 2002/05/07 03:16:44 theoddone33
129 * The Great Newline Fix
131 * Revision 1.1.1.1 2002/05/03 03:28:09 root
135 * 201 6/16/00 3:15p Jefff
136 * sim of the year dvd version changes, a few german soty localization
139 * 200 11/03/99 11:06a Jefff
142 * 199 10/26/99 5:07p Jamest
143 * fixed jeffs dumb debug code
145 * 198 10/25/99 5:53p Jefff
146 * call control_config_common_init() on startup
148 * 197 10/14/99 10:18a Daveb
149 * Fixed incorrect CD checking problem on standalone server.
151 * 196 10/13/99 9:22a Daveb
152 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
153 * related to movies. Fixed launcher spawning from PXO screen.
155 * 195 10/06/99 11:05a Jefff
156 * new oem upsell 3 hotspot coords
158 * 194 10/06/99 10:31a Jefff
161 * 193 10/01/99 9:10a Daveb
164 * 192 9/15/99 4:57a Dave
165 * Updated ships.tbl checksum
167 * 191 9/15/99 3:58a Dave
168 * Removed framerate warning at all times.
170 * 190 9/15/99 3:16a Dave
171 * Remove mt-011.fs2 from the builtin mission list.
173 * 189 9/15/99 1:45a Dave
174 * Don't init joystick on standalone. Fixed campaign mode on standalone.
175 * Fixed no-score-report problem in TvT
177 * 188 9/14/99 6:08a Dave
178 * Updated (final) single, multi, and campaign list.
180 * 187 9/14/99 3:26a Dave
181 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
182 * respawn-too-early problem. Made a few crash points safe.
184 * 186 9/13/99 4:52p Dave
187 * 185 9/12/99 8:09p Dave
188 * Fixed problem where skip-training button would cause mission messages
189 * not to get paged out for the current mission.
191 * 184 9/10/99 11:53a Dave
192 * Shutdown graphics before sound to eliminate apparent lockups when
193 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
195 * 183 9/09/99 11:40p Dave
196 * Handle an Assert() in beam code. Added supernova sounds. Play the right
197 * 2 end movies properly, based upon what the player did in the mission.
199 * 182 9/08/99 10:29p Dave
200 * Make beam sound pausing and unpausing much safer.
202 * 181 9/08/99 10:01p Dave
203 * Make sure game won't run in a drive's root directory. Make sure
204 * standalone routes suqad war messages properly to the host.
206 * 180 9/08/99 3:22p Dave
207 * Updated builtin mission list.
209 * 179 9/08/99 12:01p Jefff
210 * fixed Game_builtin_mission_list typo on Training-2.fs2
212 * 178 9/08/99 9:48a Andsager
213 * Add force feedback for engine wash.
215 * 177 9/07/99 4:01p Dave
216 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
217 * does everything properly (setting up address when binding). Remove
218 * black rectangle background from UI_INPUTBOX.
220 * 176 9/13/99 2:40a Dave
221 * Comment in full 80 minute CD check for RELEASE_REAL builds.
223 * 175 9/06/99 6:38p Dave
224 * Improved CD detection code.
226 * 174 9/06/99 1:30a Dave
227 * Intermediate checkin. Started on enforcing CD-in-drive to play the
230 * 173 9/06/99 1:16a Dave
231 * Make sure the user sees the intro movie.
233 * 172 9/04/99 8:00p Dave
234 * Fixed up 1024 and 32 bit movie support.
236 * 171 9/03/99 1:32a Dave
237 * CD checking by act. Added support to play 2 cutscenes in a row
238 * seamlessly. Fixed super low level cfile bug related to files in the
239 * root directory of a CD. Added cheat code to set campaign mission # in
242 * 170 9/01/99 10:49p Dave
243 * Added nice SquadWar checkbox to the client join wait screen.
245 * 169 9/01/99 10:14a Dave
248 * 168 8/29/99 4:51p Dave
249 * Fixed damaged checkin.
251 * 167 8/29/99 4:18p Andsager
252 * New "burst" limit for friendly damage. Also credit more damage done
253 * against large friendly ships.
255 * 166 8/27/99 6:38p Alanl
256 * crush the blasted repeating messages bug
258 * 164 8/26/99 9:09p Dave
259 * Force framerate check in everything but a RELEASE_REAL build.
261 * 163 8/26/99 9:45a Dave
262 * First pass at easter eggs and cheats.
264 * 162 8/24/99 8:55p Dave
265 * Make sure nondimming pixels work properly in tech menu.
267 * 161 8/24/99 1:49a Dave
268 * Fixed client-side afterburner stuttering. Added checkbox for no version
269 * checking on PXO join. Made button info passing more friendly between
272 * 160 8/22/99 5:53p Dave
273 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
274 * instead of ship designations for multiplayer players.
276 * 159 8/22/99 1:19p Dave
277 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
278 * which d3d cards are detected.
280 * 158 8/20/99 2:09p Dave
281 * PXO banner cycling.
283 * 157 8/19/99 10:59a Dave
284 * Packet loss detection.
286 * 156 8/19/99 10:12a Alanl
287 * preload mission-specific messages on machines greater than 48MB
289 * 155 8/16/99 4:04p Dave
290 * Big honking checkin.
292 * 154 8/11/99 5:54p Dave
293 * Fixed collision problem. Fixed standalone ghost problem.
295 * 153 8/10/99 7:59p Jefff
298 * 152 8/10/99 6:54p Dave
299 * Mad optimizations. Added paging to the nebula effect.
301 * 151 8/10/99 3:44p Jefff
302 * loads Intelligence information on startup
304 * 150 8/09/99 3:47p Dave
305 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
306 * non-nebula missions.
308 * 149 8/09/99 2:21p Andsager
309 * Fix patching from multiplayer direct to launcher update tab.
311 * 148 8/09/99 10:36a Dave
312 * Version info for game.
314 * 147 8/06/99 9:46p Dave
315 * Hopefully final changes for the demo.
317 * 146 8/06/99 3:34p Andsager
318 * Make title version info "(D)" -> "D" show up nicely
320 * 145 8/06/99 2:59p Adamp
321 * Fixed NT launcher/update problem.
323 * 144 8/06/99 1:52p Dave
324 * Bumped up MAX_BITMAPS for the demo.
326 * 143 8/06/99 12:17p Andsager
327 * Demo: down to just 1 demo dog
329 * 142 8/05/99 9:39p Dave
330 * Yet another new checksum.
332 * 141 8/05/99 6:19p Dave
333 * New demo checksums.
335 * 140 8/05/99 5:31p Andsager
336 * Up demo version 1.01
338 * 139 8/05/99 4:22p Andsager
339 * No time limit on upsell screens. Reverse order of display of upsell
342 * 138 8/05/99 4:17p Dave
343 * Tweaks to client interpolation.
345 * 137 8/05/99 3:52p Danw
347 * 136 8/05/99 3:01p Danw
349 * 135 8/05/99 2:43a Anoop
350 * removed duplicate definition.
352 * 134 8/05/99 2:13a Dave
355 * 133 8/05/99 2:05a Dave
358 * 132 8/05/99 1:22a Andsager
361 * 131 8/04/99 9:51p Andsager
362 * Add title screen to demo
364 * 130 8/04/99 6:47p Jefff
365 * fixed link error resulting from #ifdefs
367 * 129 8/04/99 6:26p Dave
368 * Updated ship tbl checksum.
370 * 128 8/04/99 5:40p Andsager
371 * Add multiple demo dogs
373 * 127 8/04/99 5:36p Andsager
374 * Show upsell screens at end of demo campaign before returning to main
377 * 126 8/04/99 11:42a Danw
378 * tone down EAX reverb
380 * 125 8/04/99 11:23a Dave
381 * Updated demo checksums.
383 * 124 8/03/99 11:02p Dave
384 * Maybe fixed sync problems in multiplayer.
386 * 123 8/03/99 6:21p Jefff
389 * 122 8/03/99 3:44p Andsager
390 * Launch laucher if trying to run FS without first having configured
393 * 121 8/03/99 12:45p Dave
396 * 120 8/02/99 9:13p Dave
399 * 119 7/30/99 10:31p Dave
400 * Added comm menu to the configurable hud files.
402 * 118 7/30/99 5:17p Andsager
403 * first fs2demo checksums
405 * 117 7/29/99 3:09p Anoop
407 * 116 7/29/99 12:05a Dave
408 * Nebula speed optimizations.
410 * 115 7/27/99 8:59a Andsager
411 * Make major, minor version consistent for all builds. Only show major
412 * and minor for launcher update window.
414 * 114 7/26/99 5:50p Dave
415 * Revised ingame join. Better? We'll see....
417 * 113 7/26/99 5:27p Andsager
418 * Add training mission as builtin to demo build
420 * 112 7/24/99 1:54p Dave
421 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
424 * 111 7/22/99 4:00p Dave
425 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
427 * 110 7/21/99 8:10p Dave
428 * First run of supernova effect.
430 * 109 7/20/99 1:49p Dave
431 * Peter Drake build. Fixed some release build warnings.
433 * 108 7/19/99 2:26p Andsager
434 * set demo multiplayer missions
436 * 107 7/18/99 5:19p Dave
437 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
439 * 106 7/16/99 1:50p Dave
440 * 8 bit aabitmaps. yay.
442 * 105 7/15/99 3:07p Dave
443 * 32 bit detection support. Mouse coord commandline.
445 * 104 7/15/99 2:13p Dave
446 * Added 32 bit detection.
448 * 103 7/15/99 9:20a Andsager
449 * FS2_DEMO initial checkin
451 * 102 7/14/99 11:02a Dave
452 * Skill level default back to easy. Blech.
454 * 101 7/09/99 5:54p Dave
455 * Seperated cruiser types into individual types. Added tons of new
456 * briefing icons. Campaign screen.
458 * 100 7/08/99 4:43p Andsager
459 * New check for sparky_hi and print if not found.
461 * 99 7/08/99 10:53a Dave
462 * New multiplayer interpolation scheme. Not 100% done yet, but still
463 * better than the old way.
465 * 98 7/06/99 4:24p Dave
466 * Mid-level checkin. Starting on some potentially cool multiplayer
469 * 97 7/06/99 3:35p Andsager
470 * Allow movie to play before red alert mission.
472 * 96 7/03/99 5:50p Dave
473 * Make rotated bitmaps draw properly in padlock views.
475 * 95 7/02/99 9:55p Dave
476 * Player engine wash sound.
478 * 94 7/02/99 4:30p Dave
479 * Much more sophisticated lightning support.
481 * 93 6/29/99 7:52p Dave
482 * Put in exception handling in FS2.
484 * 92 6/22/99 9:37p Dave
485 * Put in pof spewing.
487 * 91 6/16/99 4:06p Dave
488 * New pilot info popup. Added new draw-bitmap-as-poly function.
490 * 90 6/15/99 1:56p Andsager
491 * For release builds, allow start up in high res only with
494 * 89 6/15/99 9:34a Dave
495 * Fixed key checking in single threaded version of the stamp notification
498 * 88 6/09/99 2:55p Andsager
499 * Allow multiple asteroid subtypes (of large, medium, small) and follow
502 * 87 6/08/99 1:14a Dave
503 * Multi colored hud test.
505 * 86 6/04/99 9:52a Dave
506 * Fixed some rendering problems.
508 * 85 6/03/99 10:15p Dave
509 * Put in temporary main hall screen.
511 * 84 6/02/99 6:18p Dave
512 * Fixed TNT lockup problems! Wheeeee!
514 * 83 6/01/99 3:52p Dave
515 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
516 * dead popup, pxo find player popup, pxo private room popup.
518 * 82 5/26/99 1:28p Jasenw
519 * changed coords for loading ani
521 * 81 5/26/99 11:46a Dave
522 * Added ship-blasting lighting and made the randomization of lighting
523 * much more customizable.
525 * 80 5/24/99 5:45p Dave
526 * Added detail levels to the nebula, with a decent speedup. Split nebula
527 * lightning into its own section.
545 #include "systemvars.h"
550 #include "starfield.h"
551 #include "lighting.h"
556 #include "fireballs.h"
560 #include "floating.h"
561 #include "gamesequence.h"
563 #include "optionsmenu.h"
564 #include "playermenu.h"
565 #include "trainingmenu.h"
566 #include "techmenu.h"
569 #include "hudmessage.h"
571 #include "missiongoals.h"
572 #include "missionparse.h"
577 #include "multiutil.h"
578 #include "multimsgs.h"
582 #include "freespace.h"
583 #include "managepilot.h"
585 #include "contexthelp.h"
588 #include "missionbrief.h"
589 #include "missiondebrief.h"
591 #include "missionshipchoice.h"
593 #include "hudconfig.h"
594 #include "controlsconfig.h"
595 #include "missionmessage.h"
596 #include "missiontraining.h"
598 #include "hudtarget.h"
600 #include "eventmusic.h"
601 #include "animplay.h"
602 #include "missionweaponchoice.h"
603 #include "missionlog.h"
604 #include "audiostr.h"
606 #include "missioncampaign.h"
608 #include "missionhotkey.h"
609 #include "objectsnd.h"
610 #include "cmeasure.h"
612 #include "linklist.h"
613 #include "shockwave.h"
614 #include "afterburner.h"
619 #include "stand_gui.h"
620 #include "pcxutils.h"
621 #include "hudtargetbox.h"
622 #include "multi_xfer.h"
623 #include "hudescort.h"
624 #include "multiutil.h"
627 #include "multiteamselect.h"
630 #include "readyroom.h"
631 #include "mainhallmenu.h"
632 #include "multilag.h"
634 #include "particle.h"
636 #include "multi_ingame.h"
637 #include "snazzyui.h"
638 #include "asteroid.h"
639 #include "popupdead.h"
640 #include "multi_voice.h"
641 #include "missioncmdbrief.h"
642 #include "redalert.h"
643 #include "gameplayhelp.h"
644 #include "multilag.h"
645 #include "staticrand.h"
646 #include "multi_pmsg.h"
647 #include "levelpaging.h"
648 #include "observer.h"
649 #include "multi_pause.h"
650 #include "multi_endgame.h"
651 #include "cutscenes.h"
652 #include "multi_respawn.h"
654 #include "multi_obj.h"
655 #include "multi_log.h"
657 #include "localize.h"
658 #include "osregistry.h"
659 #include "barracks.h"
660 #include "missionpause.h"
662 #include "alphacolors.h"
663 #include "objcollide.h"
666 #include "neblightning.h"
667 #include "shipcontrails.h"
670 #include "multi_dogfight.h"
671 #include "multi_rate.h"
672 #include "muzzleflash.h"
676 #include "mainhalltemp.h"
677 #include "exceptionhandler.h"
681 #include "supernova.h"
682 #include "hudshield.h"
683 // #include "names.h"
685 #include "missionloopbrief.h"
689 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
695 // 1.00.04 5/26/98 MWA -- going final (12 pm)
696 // 1.00.03 5/26/98 MWA -- going final (3 am)
697 // 1.00.02 5/25/98 MWA -- going final
698 // 1.00.01 5/25/98 MWA -- going final
699 // 0.90 5/21/98 MWA -- getting ready for final.
700 // 0.10 4/9/98. Set by MK.
702 // Demo version: (obsolete since DEMO codebase split from tree)
703 // 0.03 4/10/98 AL. Interplay rev
704 // 0.02 4/8/98 MK. Increased when this system was modified.
705 // 0.01 4/7/98? AL. First release to Interplay QA.
708 // 1.00 5/28/98 AL. First release to Interplay QA.
710 void game_level_init(int seed = -1);
711 void game_post_level_init();
712 void game_do_frame();
713 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
714 void game_reset_time();
715 void game_show_framerate(); // draws framerate in lower right corner
717 int Game_no_clear = 0;
719 int Pofview_running = 0;
720 int Nebedit_running = 0;
722 typedef struct big_expl_flash {
723 float max_flash_intensity; // max intensity
724 float cur_flash_intensity; // cur intensity
725 int flash_start; // start time
728 #define FRAME_FILTER 16
730 #define DEFAULT_SKILL_LEVEL 1
731 int Game_skill_level = DEFAULT_SKILL_LEVEL;
733 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
734 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
736 #define EXE_FNAME ("fs2.exe")
737 #define LAUNCHER_FNAME ("freespace2.exe")
739 // JAS: Code for warphole camera.
740 // Needs to be cleaned up.
741 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
742 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
743 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
744 matrix Camera_orient = IDENTITY_MATRIX;
745 float Camera_damping = 1.0f;
746 float Camera_time = 0.0f;
747 float Warpout_time = 0.0f;
748 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
749 int Warpout_sound = -1;
751 int Use_joy_mouse = 0;
752 int Use_palette_flash = 1;
754 int Use_fullscreen_at_startup = 0;
756 int Show_area_effect = 0;
757 object *Last_view_target = NULL;
759 int dogfight_blown = 0;
762 float frametimes[FRAME_FILTER];
763 float frametotal = 0.0f;
767 int Show_framerate = 0;
769 int Show_framerate = 1;
772 int Framerate_cap = 120;
775 int Show_target_debug_info = 0;
776 int Show_target_weapons = 0;
780 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
783 int Debug_octant = -1;
785 fix Game_time_compression = F1_0;
787 // if the ships.tbl the player has is valid
788 int Game_ships_tbl_valid = 0;
790 // if the weapons.tbl the player has is valid
791 int Game_weapons_tbl_valid = 0;
795 extern int Player_attacking_enabled;
799 int Pre_player_entry;
801 int Fred_running = 0;
802 char Game_current_mission_filename[MAX_FILENAME_LEN];
803 int game_single_step = 0;
804 int last_single_step=0;
806 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
807 extern int MSG_WINDOW_Y_START;
808 extern int MSG_WINDOW_HEIGHT;
810 int game_zbuffer = 1;
811 //static int Game_music_paused;
812 static int Game_paused;
816 #define EXPIRE_BAD_CHECKSUM 1
817 #define EXPIRE_BAD_TIME 2
819 extern void ssm_init();
820 extern void ssm_level_init();
821 extern void ssm_process();
823 // static variable to contain the time this version was built
824 // commented out for now until
825 // I figure out how to get the username into the file
826 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
828 // defines and variables used for dumping frame for making trailers.
830 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
831 int Debug_dump_trigger = 0;
832 int Debug_dump_frame_count;
833 int Debug_dump_frame_num = 0;
834 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
837 // amount of time to wait after the player has died before we display the death died popup
838 #define PLAYER_DIED_POPUP_WAIT 2500
839 int Player_died_popup_wait = -1;
840 int Player_multi_died_check = -1;
842 // builtin mission list stuff
844 int Game_builtin_mission_count = 6;
845 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
846 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
847 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
848 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
849 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
850 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 #elif defined(FS1_DEMO)
854 int Game_builtin_mission_count = 5;
855 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
856 { "btmdemo.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
857 { "demo.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
858 { "demo01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
859 { "demo02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
860 { "demo02b.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
862 #elif defined(PD_BUILD)
863 int Game_builtin_mission_count = 4;
864 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
865 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
866 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
867 { "sm1-01", (FSB_FROM_VOLITION), "" },
868 { "sm1-05", (FSB_FROM_VOLITION), "" },
870 #elif defined(MULTIPLAYER_BETA)
871 int Game_builtin_mission_count = 17;
872 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
874 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
887 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
888 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
889 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
890 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
892 #elif defined(OEM_BUILD)
893 int Game_builtin_mission_count = 17;
894 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
895 // oem version - act 1 only
896 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
899 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
900 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
901 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
902 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
903 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
904 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
905 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
906 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
907 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
908 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
909 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
910 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
911 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
912 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
913 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
914 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
916 #elif defined(MAKE_FS1)
917 int Game_builtin_mission_count = 125;
918 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
919 // single player campaign
920 { "freespace.fsc", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
923 { "sm1-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
924 { "sm1-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
925 { "sm1-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
926 { "sm1-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
927 { "sm1-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
928 { "sm1-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
929 { "sm1-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
930 { "sm1-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
931 { "sm1-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
932 { "sm1-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
935 { "sm2-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
936 { "sm2-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
937 { "sm2-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
938 { "sm2-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
939 { "sm2-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
940 { "sm2-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
941 { "sm2-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
942 { "sm2-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
943 { "sm2-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
944 { "sm2-10a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
947 { "sm3-01a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
948 { "sm3-02a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
949 { "sm3-03a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
950 { "sm3-04a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
951 { "sm3-05a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
952 { "sm3-06a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
953 { "sm3-07a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
954 { "sm3-08a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
955 { "sm3-09a.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
958 { "t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "btm-01.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
964 { "btm-02.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
965 { "btm-03.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
966 { "btm-04.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
967 { "btm-05.fsm", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
970 { "m-hope.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
971 { "m-altair.fsc", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
973 { "m-v-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "m-va.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "m-unstoppable.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "m-t-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "m-s-gauntlet.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "m-rescue.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "m-pain.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "m-orecovery.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "mm3-01a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "mm3-02a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "mm3-03a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
984 { "mm3-04a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
985 { "mm3-05a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "mm3-06a.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
987 { "m-guardduty.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
988 { "m-gate.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
989 { "m-duel.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
990 { "m-convoyassault.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
991 { "m-clash.fsm", (FSB_FROM_VOLITION | FSB_MULTI), "" },
993 // SilentThreat missions
994 // Main SilentThreat campaign
995 { "SilentThreat.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN_FILE), "" },
997 { "md-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
998 { "md-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
999 { "md-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1000 { "md-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1001 { "md-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1002 { "md-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1003 { "md-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1004 { "md-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1005 { "md-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1006 { "md-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1007 { "md-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1008 { "md-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_CAMPAIGN), "" },
1010 // SilentThreat Part 1 - multi-coop
1011 { "ST-Part1.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1013 { "stmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1014 { "stmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1015 { "stmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1017 // SilentThreat Part 2 - multi-coop
1018 { "ST-Part2.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1020 { "stmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1021 { "stmm-05.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1022 { "stmm-06.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1024 // SilentThreat Part 3 - multi-coop
1025 { "ST-Part3.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1027 { "stmm-07.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1028 { "stmm-08.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1029 { "stmm-09.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1031 // SilentThreat Part 4 - multi-coop
1032 { "ST-Part4.fsc", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1034 { "stmm-10.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1035 { "stmm-11.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1036 { "stmm-12.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI | FSB_CAMPAIGN), "" },
1038 // multiplayer missions
1039 { "mdmm-01.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1040 { "mdmm-02.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1041 { "mdmm-03.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1042 { "mdmm-04.fsm", (FSB_FROM_VOLITION | FSB_FROM_MDISK | FSB_MULTI), "" },
1043 // user supplied missions
1044 { "mdu-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1045 { "mdu-03.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1046 { "mdu-04.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1047 { "mdu-05.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1048 { "mdu-06.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1049 { "mdu-07.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1050 { "mdu-08.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1051 { "mdu-09.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1052 { "mdu-10.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1053 { "mdu-11.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1054 { "mdu-12.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1055 { "mdu-13.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1056 { "mdu-14.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1057 { "mdu-15.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1058 { "mdu-16.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1059 { "mdu-17.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1060 { "mdu-18.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1061 { "mdu-19.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1062 { "mdu-20.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1063 { "mdu-21.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1064 { "mdu-22.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1065 { "mdu-23.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1066 { "mdu-24.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1067 { "mdu-25.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1068 { "mdu-26.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1069 { "mdu-27.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1070 { "mdu-28.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1071 { "mdu-29.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1072 { "mdu-30.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1073 { "mdu-31.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1074 { "mdumm-01.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1075 { "mdumm-02.fsm", (FSB_FROM_MDISK | FSB_MULTI), "" },
1078 int Game_builtin_mission_count = 92;
1079 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
1080 // single player campaign
1081 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
1084 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1085 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1086 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1087 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1088 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1089 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1090 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1091 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1092 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1093 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1094 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1095 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1096 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1097 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1098 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1099 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1100 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1101 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1102 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
1105 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1106 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1107 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1108 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1109 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1110 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1111 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1112 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1113 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1114 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1117 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1118 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1119 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1120 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1121 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1122 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1123 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1124 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1125 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1126 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1127 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1128 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
1130 // multiplayer missions
1133 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1134 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1135 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1138 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1139 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1140 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1141 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1144 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1145 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1146 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1147 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1148 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1149 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1150 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1151 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1152 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1153 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1154 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1155 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1156 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1157 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1158 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1159 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1160 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1161 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1162 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1163 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1164 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1165 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1166 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1167 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1168 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1169 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1170 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1171 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1174 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1175 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1176 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1177 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1178 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1179 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1180 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1181 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1182 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1183 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
1186 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
1187 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1188 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1189 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1190 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1195 // Internal function prototypes
1196 void game_maybe_draw_mouse(float frametime);
1197 void init_animating_pointer();
1198 void load_animating_pointer(char *filename, int dx, int dy);
1199 void unload_animating_pointer();
1200 void game_do_training_checks();
1201 void game_shutdown(void);
1202 void game_show_event_debug(float frametime);
1203 void game_event_debug_init();
1205 void demo_upsell_show_screens();
1206 void game_start_subspace_ambient_sound();
1207 void game_stop_subspace_ambient_sound();
1208 void verify_ships_tbl();
1209 void verify_weapons_tbl();
1210 void display_title_screen();
1212 // loading background filenames
1213 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1214 "LoadingBG", // GR_640
1215 "2_LoadingBG" // GR_1024
1219 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1220 "Loading.ani", // GR_640
1221 "2_Loading.ani" // GR_1024
1224 #if defined(FS2_DEMO) || defined(FS1_DEMO)
1225 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1233 #elif defined(OEM_BUILD)
1234 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1244 char Game_CDROM_dir[MAX_PATH_LEN];
1247 // How much RAM is on this machine. Set in WinMain
1248 uint Freespace_total_ram = 0;
1251 float Game_flash_red = 0.0f;
1252 float Game_flash_green = 0.0f;
1253 float Game_flash_blue = 0.0f;
1254 float Sun_spot = 0.0f;
1255 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1257 // game shudder stuff (in ms)
1258 int Game_shudder_time = -1;
1259 int Game_shudder_total = 0;
1260 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1263 sound_env Game_sound_env;
1264 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1265 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1267 int Game_sound_env_update_timestamp;
1269 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1272 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1274 fs_builtin_mission *game_find_builtin_mission(char *filename)
1278 // look through all existing builtin missions
1279 for(idx=0; idx<Game_builtin_mission_count; idx++){
1280 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1281 return &Game_builtin_mission_list[idx];
1289 int game_get_default_skill_level()
1291 return DEFAULT_SKILL_LEVEL;
1295 void game_flash_reset()
1297 Game_flash_red = 0.0f;
1298 Game_flash_green = 0.0f;
1299 Game_flash_blue = 0.0f;
1301 Big_expl_flash.max_flash_intensity = 0.0f;
1302 Big_expl_flash.cur_flash_intensity = 0.0f;
1303 Big_expl_flash.flash_start = 0;
1306 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1307 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1309 void game_framerate_check_init()
1311 // zero critical time
1312 Gf_critical_time = 0.0f;
1315 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1316 // if this is a glide card
1317 if(gr_screen.mode == GR_GLIDE){
1319 extern GrHwConfiguration hwconfig;
1322 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1323 Gf_critical = 15.0f;
1327 Gf_critical = 10.0f;
1332 Gf_critical = 15.0f;
1335 // d3d. only care about good cards here I guess (TNT)
1337 Gf_critical = 15.0f;
1340 // if this is a glide card
1341 if(gr_screen.mode == GR_GLIDE){
1343 extern GrHwConfiguration hwconfig;
1346 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1347 Gf_critical = 25.0f;
1351 Gf_critical = 20.0f;
1356 Gf_critical = 25.0f;
1359 // d3d. only care about good cards here I guess (TNT)
1361 Gf_critical = 25.0f;
1366 extern float Framerate;
1367 void game_framerate_check()
1371 // if the current framerate is above the critical level, add frametime
1372 if(Framerate >= Gf_critical){
1373 Gf_critical_time += flFrametime;
1376 if(!Show_framerate){
1380 // display if we're above the critical framerate
1381 if(Framerate < Gf_critical){
1382 gr_set_color_fast(&Color_bright_red);
1383 gr_string(200, y_start, "Framerate warning");
1388 // display our current pct of good frametime
1389 if(f2fl(Missiontime) >= 0.0f){
1390 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1393 gr_set_color_fast(&Color_bright_green);
1395 gr_set_color_fast(&Color_bright_red);
1398 gr_printf(200, y_start, "%d%%", (int)pct);
1405 // Adds a flash effect. These can be positive or negative.
1406 // The range will get capped at around -1 to 1, so stick
1407 // with a range like that.
1408 void game_flash( float r, float g, float b )
1410 Game_flash_red += r;
1411 Game_flash_green += g;
1412 Game_flash_blue += b;
1414 if ( Game_flash_red < -1.0f ) {
1415 Game_flash_red = -1.0f;
1416 } else if ( Game_flash_red > 1.0f ) {
1417 Game_flash_red = 1.0f;
1420 if ( Game_flash_green < -1.0f ) {
1421 Game_flash_green = -1.0f;
1422 } else if ( Game_flash_green > 1.0f ) {
1423 Game_flash_green = 1.0f;
1426 if ( Game_flash_blue < -1.0f ) {
1427 Game_flash_blue = -1.0f;
1428 } else if ( Game_flash_blue > 1.0f ) {
1429 Game_flash_blue = 1.0f;
1434 // Adds a flash for Big Ship explosions
1435 // cap range from 0 to 1
1436 void big_explosion_flash(float flash)
1438 Big_expl_flash.flash_start = timestamp(1);
1442 } else if (flash < 0.0f) {
1446 Big_expl_flash.max_flash_intensity = flash;
1447 Big_expl_flash.cur_flash_intensity = 0.0f;
1450 // Amount to diminish palette towards normal, per second.
1451 #define DIMINISH_RATE 0.75f
1452 #define SUN_DIMINISH_RATE 6.00f
1456 float sn_glare_scale = 1.7f;
1459 dc_get_arg(ARG_FLOAT);
1460 sn_glare_scale = Dc_arg_float;
1463 float Supernova_last_glare = 0.0f;
1464 void game_sunspot_process(float frametime)
1468 float Sun_spot_goal = 0.0f;
1471 sn_stage = supernova_active();
1473 // sunspot differently based on supernova stage
1475 // approaching. player still in control
1478 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1481 light_get_global_dir(&light_dir, 0);
1483 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1486 // scale it some more
1487 dot = dot * (0.5f + (pct * 0.5f));
1490 Sun_spot_goal += (dot * sn_glare_scale);
1493 // draw the sun glow
1494 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1495 // draw the glow for this sun
1496 stars_draw_sun_glow(0);
1499 Supernova_last_glare = Sun_spot_goal;
1502 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1505 Sun_spot_goal = 0.9f;
1506 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1508 if(Sun_spot_goal > 1.0f){
1509 Sun_spot_goal = 1.0f;
1512 Sun_spot_goal *= sn_glare_scale;
1513 Supernova_last_glare = Sun_spot_goal;
1516 // fade to white. display dead popup
1519 Supernova_last_glare += (2.0f * flFrametime);
1520 if(Supernova_last_glare > 2.0f){
1521 Supernova_last_glare = 2.0f;
1524 Sun_spot_goal = Supernova_last_glare;
1531 // check sunspots for all suns
1532 n_lights = light_get_global_count();
1535 for(idx=0; idx<n_lights; idx++){
1536 //(vector *eye_pos, matrix *eye_orient)
1537 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1540 light_get_global_dir(&light_dir, idx);
1542 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1544 Sun_spot_goal += (float)pow(dot,85.0f);
1546 // draw the glow for this sun
1547 stars_draw_sun_glow(idx);
1549 Sun_spot_goal = 0.0f;
1555 Sun_spot_goal = 0.0f;
1559 float dec_amount = frametime*SUN_DIMINISH_RATE;
1561 if ( Sun_spot < Sun_spot_goal ) {
1562 Sun_spot += dec_amount;
1563 if ( Sun_spot > Sun_spot_goal ) {
1564 Sun_spot = Sun_spot_goal;
1566 } else if ( Sun_spot > Sun_spot_goal ) {
1567 Sun_spot -= dec_amount;
1568 if ( Sun_spot < Sun_spot_goal ) {
1569 Sun_spot = Sun_spot_goal;
1575 // Call once a frame to diminish the
1576 // flash effect to 0.
1577 void game_flash_diminish(float frametime)
1579 float dec_amount = frametime*DIMINISH_RATE;
1581 if ( Game_flash_red > 0.0f ) {
1582 Game_flash_red -= dec_amount;
1583 if ( Game_flash_red < 0.0f )
1584 Game_flash_red = 0.0f;
1586 Game_flash_red += dec_amount;
1587 if ( Game_flash_red > 0.0f )
1588 Game_flash_red = 0.0f;
1591 if ( Game_flash_green > 0.0f ) {
1592 Game_flash_green -= dec_amount;
1593 if ( Game_flash_green < 0.0f )
1594 Game_flash_green = 0.0f;
1596 Game_flash_green += dec_amount;
1597 if ( Game_flash_green > 0.0f )
1598 Game_flash_green = 0.0f;
1601 if ( Game_flash_blue > 0.0f ) {
1602 Game_flash_blue -= dec_amount;
1603 if ( Game_flash_blue < 0.0f )
1604 Game_flash_blue = 0.0f;
1606 Game_flash_blue += dec_amount;
1607 if ( Game_flash_blue > 0.0f )
1608 Game_flash_blue = 0.0f;
1611 // update big_explosion_cur_flash
1612 #define TIME_UP 1500
1613 #define TIME_DOWN 2500
1614 int duration = TIME_UP + TIME_DOWN;
1615 int time = timestamp_until(Big_expl_flash.flash_start);
1616 if (time > -duration) {
1618 if (time < TIME_UP) {
1619 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1622 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1626 if ( Use_palette_flash ) {
1628 // static int or=0, og=0, ob=0;
1630 // Change the 200 to change the color range of colors.
1631 r = fl2i( Game_flash_red*128.0f );
1632 g = fl2i( Game_flash_green*128.0f );
1633 b = fl2i( Game_flash_blue*128.0f );
1635 if ( Sun_spot > 0.0f ) {
1636 r += fl2i(Sun_spot*128.0f);
1637 g += fl2i(Sun_spot*128.0f);
1638 b += fl2i(Sun_spot*128.0f);
1641 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1642 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1643 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1644 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1647 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1648 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1649 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1651 if ( (r!=0) || (g!=0) || (b!=0) ) {
1652 gr_flash( r, g, b );
1654 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1665 void game_level_close()
1667 // De-Initialize the game subsystems
1668 event_music_level_close();
1669 game_stop_looped_sounds();
1671 obj_snd_level_close(); // uninit object-linked persistant sounds
1672 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1673 anim_level_close(); // stop and clean up any anim instances
1674 message_mission_shutdown(); // called after anim_level_close() to make sure anim instances are free
1675 shockwave_level_close();
1676 fireball_level_close();
1678 mission_event_shutdown();
1679 asteroid_level_close();
1680 model_cache_reset(); // Reset/free all the model caching stuff
1681 flak_level_close(); // unload flak stuff
1682 neb2_level_close(); // shutdown gaseous nebula stuff
1685 mflash_level_close();
1687 audiostream_unpause_all();
1692 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1693 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1694 void game_level_init(int seed)
1696 // seed the random number generator
1698 // if no seed was passed, seed the generator either from the time value, or from the
1699 // netgame security flags -- ensures that all players in multiplayer game will have the
1700 // same randon number sequence (with static rand functions)
1701 if ( Game_mode & GM_NORMAL ) {
1702 Game_level_seed = time(NULL);
1704 Game_level_seed = Netgame.security;
1707 // mwa 9/17/98 -- maybe this assert isn't needed????
1708 Assert( !(Game_mode & GM_MULTIPLAYER) );
1709 Game_level_seed = seed;
1711 srand( Game_level_seed );
1713 // semirand function needs to get re-initted every time in multiplayer
1714 if ( Game_mode & GM_MULTIPLAYER ){
1720 Key_normal_game = (Game_mode & GM_NORMAL);
1723 Game_shudder_time = -1;
1725 // Initialize the game subsystems
1726 // timestamp_reset(); // Must be inited before everything else
1728 game_reset_time(); // resets time, and resets saved time too
1730 obj_init(); // Must be inited before the other systems
1731 model_free_all(); // Free all existing models
1732 mission_brief_common_init(); // Free all existing briefing/debriefing text
1733 weapon_level_init();
1734 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1736 player_level_init();
1737 shipfx_flash_init(); // Init the ship gun flash system.
1738 game_flash_reset(); // Reset the flash effect
1739 particle_init(); // Reset the particle system
1743 shield_hit_init(); // Initialize system for showing shield hits
1744 radar_mission_init();
1745 mission_init_goals();
1748 obj_snd_level_init(); // init object-linked persistant sounds
1750 shockwave_level_init();
1751 afterburner_level_init();
1752 scoring_level_init( &Player->stats );
1754 asteroid_level_init();
1755 control_config_clear_used_status();
1756 collide_ship_ship_sounds_init();
1758 Pre_player_entry = 1; // Means the player has not yet entered.
1759 Entry_delay_time = 0; // Could get overwritten in mission read.
1760 fireball_preload(); // page in warphole bitmaps
1762 flak_level_init(); // initialize flak - bitmaps, etc
1763 ct_level_init(); // initialize ships contrails, etc
1764 awacs_level_init(); // initialize AWACS
1765 beam_level_init(); // initialize beam weapons
1766 mflash_level_init();
1768 supernova_level_init();
1770 // multiplayer dogfight hack
1773 shipfx_engine_wash_level_init();
1777 Last_view_target = NULL;
1782 // campaign wasn't ended
1783 Campaign_ended_in_mission = 0;
1786 // called when a mission is over -- does server specific stuff.
1787 void freespace_stop_mission()
1790 Game_mode &= ~GM_IN_MISSION;
1793 // called at frame interval to process networking stuff
1794 void game_do_networking()
1796 Assert( Net_player != NULL );
1797 if (!(Game_mode & GM_MULTIPLAYER)){
1801 // see if this player should be reading/writing data. Bit is set when at join
1802 // screen onward until quits back to main menu.
1803 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1807 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1810 multi_pause_do_frame();
1815 // Loads the best palette for this level, based
1816 // on nebula color and hud color. You could just call palette_load_table with
1817 // the appropriate filename, but who wants to do that.
1818 void game_load_palette()
1820 char palette_filename[1024];
1822 // We only use 3 hud colors right now
1824 Assert( HUD_config.main_color >= 0 );
1825 Assert( HUD_config.main_color <= 2 );
1828 Assert( Mission_palette >= 0 );
1829 Assert( Mission_palette <= 98 );
1832 if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1833 strcpy( palette_filename, NOX("gamepalette-subspace") );
1835 sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.main_color+1, Mission_palette+1 );
1838 mprintf(( "Loading palette %s\n", palette_filename ));
1840 palette_load_table(palette_filename);
1842 strcpy( palette_filename, NOX("gamepalette-subspace") );
1844 mprintf(( "Loading palette %s\n", palette_filename ));
1848 void game_post_level_init()
1850 // Stuff which gets called after mission is loaded. Because player isn't created until
1851 // after mission loads, some things must get initted after the level loads
1853 model_level_post_init();
1856 hud_setup_escort_list();
1857 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1863 game_event_debug_init();
1866 training_mission_init();
1867 asteroid_create_all();
1869 game_framerate_check_init();
1873 // An estimate as to how high the count passed to game_loading_callback will go.
1874 // This is just a guess, it seems to always be about the same. The count is
1875 // proportional to the code being executed, not the time, so this works good
1876 // for a bar, assuming the code does about the same thing each time you
1877 // load a level. You can find this value by looking at the return value
1878 // of game_busy_callback(NULL), which I conveniently print out to the
1879 // debug output window with the '=== ENDING LOAD ==' stuff.
1880 //#define COUNT_ESTIMATE 3706
1881 #define COUNT_ESTIMATE 1111
1883 int Game_loading_callback_inited = 0;
1885 int Game_loading_background = -1;
1886 anim * Game_loading_ani = NULL;
1887 anim_instance *Game_loading_ani_instance;
1888 int Game_loading_frame=-1;
1890 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1892 #if defined(FS1_DEMO)
1894 #elif defined(MAKE_FS1)
1905 // This gets called 10x per second and count is the number of times
1906 // game_busy() has been called since the current callback function
1908 void game_loading_callback(int count)
1910 game_do_networking();
1912 Assert( Game_loading_callback_inited==1 );
1913 Assert( Game_loading_ani != NULL );
1915 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1916 if ( framenum > Game_loading_ani->total_frames-1 ) {
1917 framenum = Game_loading_ani->total_frames-1;
1918 } else if ( framenum < 0 ) {
1923 while ( Game_loading_frame < framenum ) {
1924 Game_loading_frame++;
1925 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1929 if ( cbitmap > -1 ) {
1930 if ( Game_loading_background > -1 ) {
1931 gr_set_bitmap( Game_loading_background );
1935 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1936 gr_set_bitmap( cbitmap );
1937 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1939 bm_release(cbitmap);
1945 void game_loading_callback_init()
1947 Assert( Game_loading_callback_inited==0 );
1949 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1951 common_set_interface_palette("InterfacePalette"); // set the interface palette
1955 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1956 Assert( Game_loading_ani != NULL );
1957 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1958 Assert( Game_loading_ani_instance != NULL );
1959 Game_loading_frame = -1;
1961 Game_loading_callback_inited = 1;
1963 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1968 void game_loading_callback_close()
1970 Assert( Game_loading_callback_inited==1 );
1972 // Make sure bar shows all the way over.
1973 game_loading_callback(COUNT_ESTIMATE);
1975 int real_count = game_busy_callback( NULL );
1978 Game_loading_callback_inited = 0;
1981 mprintf(( "=================== ENDING LOAD ================\n" ));
1982 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1983 mprintf(( "================================================\n" ));
1985 // to remove warnings in release build
1989 free_anim_instance(Game_loading_ani_instance);
1990 Game_loading_ani_instance = NULL;
1991 anim_free(Game_loading_ani);
1992 Game_loading_ani = NULL;
1994 bm_release( Game_loading_background );
1995 common_free_interface_palette(); // restore game palette
1996 Game_loading_background = -1;
1998 gr_set_font( FONT1 );
2001 // Update the sound environment (ie change EAX settings based on proximity to large ships)
2003 void game_maybe_update_sound_environment()
2005 // do nothing for now
2008 // Assign the sound environment for the game, based on the current mission
2010 void game_assign_sound_environment()
2013 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
2014 Game_sound_env.id = SND_ENV_DRUGGED;
2015 Game_sound_env.volume = 0.800f;
2016 Game_sound_env.damping = 1.188f;
2017 Game_sound_env.decay = 6.392f;
2019 } else if (Num_asteroids > 30) {
2020 Game_sound_env.id = SND_ENV_AUDITORIUM;
2021 Game_sound_env.volume = 0.603f;
2022 Game_sound_env.damping = 0.5f;
2023 Game_sound_env.decay = 4.279f;
2026 Game_sound_env = Game_default_sound_env;
2030 Game_sound_env = Game_default_sound_env;
2031 Game_sound_env_update_timestamp = timestamp(1);
2034 // function which gets called before actually entering the mission. It is broken down into a funciton
2035 // since it will get called in one place from a single player game and from another place for
2036 // a multiplayer game
2037 void freespace_mission_load_stuff()
2039 // called if we're not on a freespace dedicated (non rendering, no pilot) server
2040 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
2041 if(!(Game_mode & GM_STANDALONE_SERVER)){
2043 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
2045 game_loading_callback_init();
2047 event_music_level_init(); // preloads the first 2 seconds for each event music track
2050 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
2053 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
2056 ship_assign_sound_all(); // assign engine sounds to ships
2057 game_assign_sound_environment(); // assign the sound environment for this mission
2060 // call function in missionparse.cpp to fixup player/ai stuff.
2061 mission_parse_fixup_players();
2064 // Load in all the bitmaps for this level
2069 game_loading_callback_close();
2071 // the only thing we need to call on the standalone for now.
2073 // call function in missionparse.cpp to fixup player/ai stuff.
2074 mission_parse_fixup_players();
2076 // Load in all the bitmaps for this level
2082 uint load_mission_load;
2083 uint load_post_level_init;
2084 uint load_mission_stuff;
2086 // tells the server to load the mission and initialize structures
2087 int game_start_mission()
2089 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
2091 load_gl_init = time(NULL);
2093 load_gl_init = time(NULL) - load_gl_init;
2095 if (Game_mode & GM_MULTIPLAYER) {
2096 Player->flags |= PLAYER_FLAGS_IS_MULTI;
2098 // clear multiplayer stats
2099 init_multiplayer_stats();
2102 load_mission_load = time(NULL);
2103 if (mission_load()) {
2104 if ( !(Game_mode & GM_MULTIPLAYER) ) {
2105 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
2106 gameseq_post_event(GS_EVENT_MAIN_MENU);
2108 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
2113 load_mission_load = time(NULL) - load_mission_load;
2115 // If this is a red alert mission in campaign mode, bash wingman status
2116 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
2117 red_alert_bash_wingman_status();
2120 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
2121 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
2122 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
2124 game_load_palette();
2128 load_post_level_init = time(NULL);
2129 game_post_level_init();
2130 load_post_level_init = time(NULL) - load_post_level_init;
2134 void Do_model_timings_test();
2135 Do_model_timings_test();
2139 load_mission_stuff = time(NULL);
2140 freespace_mission_load_stuff();
2141 load_mission_stuff = time(NULL) - load_mission_stuff;
2146 int Interface_framerate = 0;
2149 DCF_BOOL( mouse_control, Use_mouse_to_fly )
2150 DCF_BOOL( show_framerate, Show_framerate )
2151 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
2152 DCF_BOOL( show_target_weapons, Show_target_weapons )
2153 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
2154 DCF_BOOL( sound, Sound_enabled )
2155 DCF_BOOL( zbuffer, game_zbuffer )
2156 DCF_BOOL( shield_system, New_shield_system )
2157 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
2158 DCF_BOOL( player_attacking, Player_attacking_enabled )
2159 DCF_BOOL( show_waypoints, Show_waypoints )
2160 DCF_BOOL( show_area_effect, Show_area_effect )
2161 DCF_BOOL( show_net_stats, Show_net_stats )
2162 DCF_BOOL( log, Log_debug_output_to_file )
2163 DCF_BOOL( training_msg_method, Training_msg_method )
2164 DCF_BOOL( show_player_pos, Show_player_pos )
2165 DCF_BOOL(i_framerate, Interface_framerate )
2167 DCF(show_mem,"Toggles showing mem usage")
2170 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2171 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
2172 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
2173 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
2179 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
2181 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2182 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2186 DCF(show_cpu,"Toggles showing cpu usage")
2189 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2190 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
2191 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
2192 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
2198 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
2200 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
2201 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
2208 // AL 4-8-98: always allow players to display their framerate
2211 DCF_BOOL( show_framerate, Show_framerate )
2218 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2221 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2222 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2223 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2224 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2226 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" );
2227 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2229 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2232 DCF(palette_flash,"Toggles palette flash effect on/off")
2235 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2236 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2237 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2238 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2240 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2241 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2244 int Use_low_mem = 0;
2246 DCF(low_mem,"Uses low memory settings regardless of RAM")
2249 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2250 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2251 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2252 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2254 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2255 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2257 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2263 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2266 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2267 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2268 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2269 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2271 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2272 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2273 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2277 int Framerate_delay = 0;
2279 float Freespace_gamma = 1.0f;
2281 DCF(gamma,"Sets Gamma factor")
2284 dc_get_arg(ARG_FLOAT|ARG_NONE);
2285 if ( Dc_arg_type & ARG_FLOAT ) {
2286 Freespace_gamma = Dc_arg_float;
2288 dc_printf( "Gamma reset to 1.0f\n" );
2289 Freespace_gamma = 1.0f;
2291 if ( Freespace_gamma < 0.1f ) {
2292 Freespace_gamma = 0.1f;
2293 } else if ( Freespace_gamma > 5.0f ) {
2294 Freespace_gamma = 5.0f;
2296 gr_set_gamma(Freespace_gamma);
2298 char tmp_gamma_string[32];
2299 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2300 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2304 dc_printf( "Usage: gamma <float>\n" );
2305 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2306 Dc_status = 0; // don't print status if help is printed. Too messy.
2310 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2319 Game_current_mission_filename[0] = 0;
2321 // seed the random number generator
2322 Game_init_seed = time(NULL);
2323 srand( Game_init_seed );
2325 Framerate_delay = 0;
2331 extern void bm_init();
2337 // Initialize the timer before the os
2345 GetCurrentDirectory(1024, whee);
2348 getcwd (whee, 1024);
2351 strcat(whee, EXE_FNAME);
2353 //Initialize the libraries
2354 s1 = timer_get_milliseconds();
2355 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2358 e1 = timer_get_milliseconds();
2360 // time a bunch of cfopens
2362 s2 = timer_get_milliseconds();
2364 for(int idx=0; idx<10000; idx++){
2365 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2370 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2372 e2 = timer_get_milliseconds();
2375 if (Is_standalone) {
2376 std_init_standalone();
2378 os_init( Osreg_class_name, Osreg_app_name );
2379 os_set_title(Osreg_title);
2382 // initialize localization module. Make sure this is down AFTER initialzing OS.
2383 // int t1 = timer_get_milliseconds();
2384 lcl_init( detect_lang() );
2386 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2388 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2391 // verify that he has a valid weapons.tbl
2392 verify_weapons_tbl();
2395 // setup the default osreg values if they don't exist
2399 // Output version numbers to registry for auto patching purposes
2400 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2401 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2402 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2404 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2405 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2406 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2409 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2412 #if defined (PLAT_UNIX) && defined(RELEASE_REAL)
2413 // show the FPS counter if the config file says so
2414 Show_framerate = os_config_read_uint( NULL, NOX("ShowFPS"), 0 );
2417 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2418 Asteroids_enabled = 1;
2421 /////////////////////////////
2423 /////////////////////////////
2428 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2429 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2431 if (!stricmp(ptr, NOX("no sound"))) {
2432 Cmdline_freespace_no_sound = 1;
2434 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2436 } else if (!stricmp(ptr, NOX("EAX"))) {
2441 if (!Is_standalone) {
2442 snd_init(use_a3d, use_eax);
2444 /////////////////////////////
2446 /////////////////////////////
2448 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2451 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);
2453 // fire up the UpdateLauncher executable
2455 PROCESS_INFORMATION pi;
2457 memset( &si, 0, sizeof(STARTUPINFO) );
2460 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2461 NULL, // pointer to command line string
2462 NULL, // pointer to process security attributes
2463 NULL, // pointer to thread security attributes
2464 FALSE, // handle inheritance flag
2465 CREATE_DEFAULT_ERROR_MODE, // creation flags
2466 NULL, // pointer to new environment block
2467 NULL, // pointer to current directory name
2468 &si, // pointer to STARTUPINFO
2469 &pi // pointer to PROCESS_INFORMATION
2472 // If the Launcher could not be started up, let the user know
2474 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2483 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2485 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);
2493 // check for hi res pack file
2494 int has_sparky_hi = 0;
2496 // check if sparky_hi exists -- access mode 0 means does file exist
2497 #ifndef MAKE_FS1 // shoudn't have it so don't check
2500 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2503 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2507 // see if we've got 32 bit in the string
2508 if(strstr(ptr, "32 bit")){
2515 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2517 // always 640 for E3
2518 gr_init(GR_640, GR_GLIDE);
2520 // regular or hi-res ?
2522 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2524 if(strstr(ptr, NOX("(1024x768)"))){
2526 gr_init(GR_1024, GR_GLIDE);
2528 gr_init(GR_640, GR_GLIDE);
2531 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2533 // always 640 for E3
2535 gr_init(GR_640, GR_DIRECT3D, depth);
2537 // regular or hi-res ?
2539 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2541 if(strstr(ptr, NOX("(1024x768)"))){
2545 gr_init(GR_1024, GR_DIRECT3D, depth);
2549 gr_init(GR_640, GR_DIRECT3D, depth);
2555 if ( Use_fullscreen_at_startup && !Is_standalone) {
2556 gr_init(GR_640, GR_DIRECTDRAW);
2558 gr_init(GR_640, GR_SOFTWARE);
2561 if ( !Is_standalone ) {
2562 gr_init(GR_640, GR_DIRECTDRAW);
2564 gr_init(GR_640, GR_SOFTWARE);
2569 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2570 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2571 gr_init(GR_1024, GR_OPENGL);
2573 gr_init(GR_640, GR_OPENGL);
2577 gr_init(GR_640, GR_SOFTWARE);
2582 extern int Gr_inited;
2583 if(trying_d3d && !Gr_inited){
2585 extern char Device_init_error[512];
2586 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2595 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2596 Freespace_gamma = (float)atof(ptr);
2597 if ( Freespace_gamma == 0.0f ) {
2598 Freespace_gamma = 1.80f;
2599 } else if ( Freespace_gamma < 0.1f ) {
2600 Freespace_gamma = 0.1f;
2601 } else if ( Freespace_gamma > 5.0f ) {
2602 Freespace_gamma = 5.0f;
2604 char tmp_gamma_string[32];
2605 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2606 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2608 gr_set_gamma(Freespace_gamma);
2610 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2613 display_title_screen();
2617 // attempt to load up master tracker registry info (login and password)
2618 Multi_tracker_id = -1;
2620 // pxo login and password
2621 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2623 nprintf(("Network","Error reading in PXO login data\n"));
2624 strcpy(Multi_tracker_login,"");
2626 strcpy(Multi_tracker_login,ptr);
2628 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2630 nprintf(("Network","Error reading PXO password\n"));
2631 strcpy(Multi_tracker_passwd,"");
2633 strcpy(Multi_tracker_passwd,ptr);
2636 // pxo squad name and password
2637 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2639 nprintf(("Network","Error reading in PXO squad name\n"));
2640 strcpy(Multi_tracker_squad_name, "");
2642 strcpy(Multi_tracker_squad_name, ptr);
2645 // If less than 48MB of RAM, use low memory model.
2648 (Freespace_total_ram < 48*1024*1024) ||
2651 mprintf(( "Using normal memory settings...\n" ));
2652 bm_set_low_mem(1); // Use every other frame of bitmaps
2654 mprintf(( "Using high memory settings...\n" ));
2655 bm_set_low_mem(0); // Use all frames of bitmaps
2658 // load non-darkening pixel defs
2659 palman_load_pixels();
2661 // hud shield icon stuff
2662 hud_shield_game_init();
2664 control_config_common_init(); // sets up localization stuff in the control config
2670 gamesnd_parse_soundstbl();
2675 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2680 player_controls_init();
2683 //if(!Is_standalone){
2691 ship_init(); // read in ships.tbl
2693 mission_campaign_init(); // load in the default campaign
2695 // navmap_init(); // init the navigation map system
2696 context_help_init();
2697 techroom_intel_init(); // parse species.tbl, load intel info
2699 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2700 init_animating_pointer();
2702 mission_brief_common_init(); // Mark all the briefing structures as empty.
2703 gr_font_init(); // loads up all fonts
2705 neb2_init(); // fullneb stuff
2709 player_tips_init(); // helpful tips
2712 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2713 pilot_load_pic_list();
2714 pilot_load_squad_pic_list();
2716 load_animating_pointer(NOX("cursor"), 0, 0);
2718 // initialize alpha colors
2719 alpha_colors_init();
2722 // Game_music_paused = 0;
2729 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2730 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2732 mprintf(("cfile_init() took %d\n", e1 - s1));
2733 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2736 char transfer_text[128];
2738 float Start_time = 0.0f;
2740 float Framerate = 0.0f;
2742 float Timing_total = 0.0f;
2743 float Timing_render2 = 0.0f;
2744 float Timing_render3 = 0.0f;
2745 float Timing_flip = 0.0f;
2746 float Timing_clear = 0.0f;
2748 MONITOR(NumPolysDrawn);
2754 void game_get_framerate()
2756 char text[128] = "";
2758 if ( frame_int == -1 ) {
2760 for (i=0; i<FRAME_FILTER; i++ ) {
2761 frametimes[i] = 0.0f;
2766 frametotal -= frametimes[frame_int];
2767 frametotal += flFrametime;
2768 frametimes[frame_int] = flFrametime;
2769 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2771 if ( frametotal != 0.0 ) {
2772 if ( Framecount >= FRAME_FILTER )
2773 Framerate = FRAME_FILTER / frametotal;
2775 Framerate = Framecount / frametotal;
2776 sprintf( text, NOX("FPS: %.1f"), Framerate );
2778 sprintf( text, NOX("FPS: ?") );
2782 if (Show_framerate) {
2783 gr_set_color_fast(&HUD_color_debug);
2784 gr_string( 570, 2, text );
2788 void game_show_framerate()
2792 cur_time = f2fl(timer_get_approx_seconds());
2793 if (cur_time - Start_time > 30.0f) {
2794 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2795 Start_time += 1000.0f;
2798 //mprintf(( "%s\n", text ));
2801 if ( Debug_dump_frames )
2805 // possibly show control checking info
2806 control_check_indicate();
2808 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2809 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2810 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2811 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2814 if ( Show_cpu == 1 ) {
2819 dy = gr_get_font_height() + 1;
2821 gr_set_color_fast(&HUD_color_debug);
2825 extern int D3D_textures_in;
2826 extern int D3D_textures_in_frame;
2827 extern int Glide_textures_in;
2828 extern int Glide_textures_in_frame;
2829 extern int Glide_explosion_vram;
2830 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2832 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2834 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2838 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2840 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2842 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2844 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2846 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2851 extern int Num_pairs; // Number of object pairs that were checked.
2852 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2855 extern int Num_pairs_checked; // What percent of object pairs were checked.
2856 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2858 Num_pairs_checked = 0;
2862 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2865 if ( Timing_total > 0.01f ) {
2866 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2868 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2870 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2872 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2874 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2884 dy = gr_get_font_height() + 1;
2886 gr_set_color_fast(&HUD_color_debug);
2889 extern int TotalRam;
2890 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2895 extern int Model_ram;
2896 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2900 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2902 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2904 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2908 extern int D3D_textures_in;
2909 extern int Glide_textures_in;
2910 extern int Glide_textures_in_frame;
2911 extern int Glide_explosion_vram;
2912 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2914 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2916 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2923 if ( Show_player_pos ) {
2927 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));
2930 MONITOR_INC(NumPolys, modelstats_num_polys);
2931 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2932 MONITOR_INC(NumVerts, modelstats_num_verts );
2934 modelstats_num_polys = 0;
2935 modelstats_num_polys_drawn = 0;
2936 modelstats_num_verts = 0;
2937 modelstats_num_sortnorms = 0;
2941 void game_show_standalone_framerate()
2943 float frame_rate=30.0f;
2944 if ( frame_int == -1 ) {
2946 for (i=0; i<FRAME_FILTER; i++ ) {
2947 frametimes[i] = 0.0f;
2952 frametotal -= frametimes[frame_int];
2953 frametotal += flFrametime;
2954 frametimes[frame_int] = flFrametime;
2955 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2957 if ( frametotal != 0.0 ) {
2958 if ( Framecount >= FRAME_FILTER ){
2959 frame_rate = FRAME_FILTER / frametotal;
2961 frame_rate = Framecount / frametotal;
2964 std_set_standalone_fps(frame_rate);
2968 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2969 void game_show_time_left()
2973 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2974 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2975 // checking how much time is left
2977 if ( Mission_end_time == -1 ){
2981 diff = f2i(Mission_end_time - Missiontime);
2982 // be sure to bash to 0. diff could be negative on frame that we quit mission
2987 hud_set_default_color();
2988 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2991 //========================================================================================
2992 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2993 //========================================================================================
2997 DCF(ai_pause,"Pauses ai")
3000 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3001 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
3002 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
3003 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
3006 obj_init_all_ships_physics();
3009 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
3010 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
3013 DCF(single_step,"Single steps the game")
3016 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
3017 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
3018 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
3019 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
3021 last_single_step = 0; // Make so single step waits a frame before stepping
3024 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
3025 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
3028 DCF_BOOL(physics_pause, physics_paused)
3029 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
3030 DCF_BOOL(ai_firing, Ai_firing_enabled )
3032 // Create some simple aliases to these commands...
3033 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
3034 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
3035 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
3036 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
3037 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
3040 //========================================================================================
3041 //========================================================================================
3044 void game_training_pause_do()
3048 key = game_check_key();
3050 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
3057 void game_increase_skill_level()
3060 if (Game_skill_level >= NUM_SKILL_LEVELS){
3061 Game_skill_level = 0;
3065 int Player_died_time;
3067 int View_percent = 100;
3070 DCF(view, "Sets the percent of the 3d view to render.")
3073 dc_get_arg(ARG_INT);
3074 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
3075 View_percent = Dc_arg_int;
3077 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
3083 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
3087 dc_printf("View is set to %d%%\n", View_percent );
3092 // Set the clip region for the 3d rendering window
3093 void game_set_view_clip()
3095 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
3096 // Set the clip region for the letterbox "dead view"
3097 int yborder = gr_screen.max_h/4;
3099 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
3100 // J.S. I've changed my ways!! See the new "no constants" code!!!
3101 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
3103 // Set the clip region for normal view
3104 if ( View_percent >= 100 ) {
3107 int xborder, yborder;
3109 if ( View_percent < 5 ) {
3113 float fp = i2fl(View_percent)/100.0f;
3114 int fi = fl2i(fl_sqrt(fp)*100.0f);
3115 if ( fi > 100 ) fi=100;
3117 xborder = ( gr_screen.max_w*(100-fi) )/200;
3118 yborder = ( gr_screen.max_h*(100-fi) )/200;
3120 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
3126 void show_debug_stuff()
3129 int laser_count = 0, missile_count = 0;
3131 for (i=0; i<MAX_OBJECTS; i++) {
3132 if (Objects[i].type == OBJ_WEAPON){
3133 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
3135 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
3141 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
3144 extern int Tool_enabled;
3149 int tst_bitmap = -1;
3151 float tst_offset, tst_offset_total;
3154 void game_tst_frame_pre()
3162 g3_rotate_vertex(&v, &tst_pos);
3163 g3_project_vertex(&v);
3166 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
3170 // big ship? always tst
3172 // within 3000 meters
3173 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
3177 // within 300 meters
3178 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
3185 void game_tst_frame()
3195 tst_time = time(NULL);
3197 // load the tst bitmap
3198 switch((int)frand_range(0.0f, 3.0)){
3200 tst_bitmap = bm_load("ig_jim");
3202 mprintf(("TST 0\n"));
3206 tst_bitmap = bm_load("ig_kan");
3208 mprintf(("TST 1\n"));
3212 tst_bitmap = bm_load("ig_jim");
3214 mprintf(("TST 2\n"));
3218 tst_bitmap = bm_load("ig_kan");
3220 mprintf(("TST 3\n"));
3229 // get the tst bitmap dimensions
3231 bm_get_info(tst_bitmap, &w, &h);
3234 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3236 snd_play(&Snds[SND_VASUDAN_BUP]);
3238 // tst x and direction
3242 tst_offset_total = (float)w;
3243 tst_offset = (float)w;
3245 tst_x = (float)gr_screen.max_w;
3246 tst_offset_total = (float)-w;
3247 tst_offset = (float)w;
3255 float diff = (tst_offset_total / 0.5f) * flFrametime;
3261 tst_offset -= fl_abs(diff);
3262 } else if(tst_mode == 2){
3265 tst_offset -= fl_abs(diff);
3269 gr_set_bitmap(tst_bitmap);
3270 gr_bitmap((int)tst_x, (int)tst_y);
3273 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3277 // if we passed the switch point
3278 if(tst_offset <= 0.0f){
3283 tst_stamp = timestamp(1000);
3284 tst_offset = fl_abs(tst_offset_total);
3295 void game_tst_mark(object *objp, ship *shipp)
3304 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3307 sip = &Ship_info[shipp->ship_info_index];
3314 tst_pos = objp->pos;
3315 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3321 extern void render_shields();
3323 void player_repair_frame(float frametime)
3325 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3327 for(idx=0;idx<MAX_PLAYERS;idx++){
3330 np = &Net_players[idx];
3332 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)){
3334 // don't rearm/repair if the player is dead or dying/departing
3335 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3336 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3341 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3342 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3348 #define NUM_FRAMES_TEST 300
3349 #define NUM_MIXED_SOUNDS 16
3350 void do_timing_test(float flFrametime)
3352 static int framecount = 0;
3353 static int test_running = 0;
3354 static float test_time = 0.0f;
3356 static int snds[NUM_MIXED_SOUNDS];
3359 if ( test_running ) {
3361 test_time += flFrametime;
3362 if ( framecount >= NUM_FRAMES_TEST ) {
3364 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3365 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3370 if ( Test_begin == 1 ) {
3376 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3379 // start looping digital sounds
3380 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3381 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3388 DCF(dcf_fov, "Change the field of view")
3391 dc_get_arg(ARG_FLOAT|ARG_NONE);
3392 if ( Dc_arg_type & ARG_NONE ) {
3393 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3394 dc_printf( "Zoom factor reset\n" );
3396 if ( Dc_arg_type & ARG_FLOAT ) {
3397 if (Dc_arg_float < 0.25f) {
3398 Viewer_zoom = 0.25f;
3399 dc_printf("Zoom factor pinned at 0.25.\n");
3400 } else if (Dc_arg_float > 1.25f) {
3401 Viewer_zoom = 1.25f;
3402 dc_printf("Zoom factor pinned at 1.25.\n");
3404 Viewer_zoom = Dc_arg_float;
3410 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3413 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3417 DCF(framerate_cap, "Sets the framerate cap")
3420 dc_get_arg(ARG_INT);
3421 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3422 Framerate_cap = Dc_arg_int;
3424 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3430 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3431 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3432 dc_printf("[n] must be from 1 to 120.\n");
3436 if ( Framerate_cap )
3437 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3439 dc_printf("There is no framerate cap currently active.\n");
3443 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3444 int Show_viewing_from_self = 0;
3446 void say_view_target()
3448 object *view_target;
3450 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3451 view_target = &Objects[Player_ai->target_objnum];
3453 view_target = Player_obj;
3455 if (Game_mode & GM_DEAD) {
3456 if (Player_ai->target_objnum != -1)
3457 view_target = &Objects[Player_ai->target_objnum];
3460 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3461 if (view_target != Player_obj){
3463 char *view_target_name = NULL;
3464 switch(Objects[Player_ai->target_objnum].type) {
3466 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3469 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3470 Viewer_mode &= ~VM_OTHER_SHIP;
3472 case OBJ_JUMP_NODE: {
3473 char jump_node_name[128];
3474 strcpy(jump_node_name, XSTR( "jump node", 184));
3475 view_target_name = jump_node_name;
3476 Viewer_mode &= ~VM_OTHER_SHIP;
3485 if ( view_target_name ) {
3486 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3487 Show_viewing_from_self = 1;
3490 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3491 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3492 Show_viewing_from_self = 1;
3494 if (Show_viewing_from_self)
3495 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3500 Last_view_target = view_target;
3504 float Game_hit_x = 0.0f;
3505 float Game_hit_y = 0.0f;
3507 // Reset at the beginning of each frame
3508 void game_whack_reset()
3514 // Apply a 2d whack to the player
3515 void game_whack_apply( float x, float y )
3517 // Do some force feedback
3518 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3524 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3527 // call to apply a "shudder"
3528 void game_shudder_apply(int time, float intensity)
3530 Game_shudder_time = timestamp(time);
3531 Game_shudder_total = time;
3532 Game_shudder_intensity = intensity;
3535 #define FF_SCALE 10000
3536 void apply_hud_shake(matrix *eye_orient)
3538 if (Viewer_obj == Player_obj) {
3539 physics_info *pi = &Player_obj->phys_info;
3547 // Make eye shake due to afterburner
3548 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3551 dtime = timestamp_until(pi->afterburner_decay);
3555 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3556 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3559 // Make eye shake due to engine wash
3561 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3564 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3565 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3567 // get the intensity
3568 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3572 vm_vec_rand_vec_quick(&rand_vec);
3575 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3579 // make hud shake due to shuddering
3580 if(Game_shudder_time != -1){
3581 // if the timestamp has elapsed
3582 if(timestamp_elapsed(Game_shudder_time)){
3583 Game_shudder_time = -1;
3585 // otherwise apply some shudder
3589 dtime = timestamp_until(Game_shudder_time);
3593 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));
3594 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));
3599 vm_angles_2_matrix(&tm, &tangles);
3600 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3601 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3602 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3603 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3608 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3610 // Player's velocity just before he blew up. Used to keep camera target moving.
3611 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3613 // Set eye_pos and eye_orient based on view mode.
3614 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3618 static int last_Viewer_mode = 0;
3619 static int last_Game_mode = 0;
3620 static int last_Viewer_objnum = -1;
3622 // This code is supposed to detect camera "cuts"... like going between
3625 // determine if we need to regenerate the nebula
3626 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3627 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3628 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3629 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3630 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3631 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3632 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3633 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3634 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3637 // regenerate the nebula
3641 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3642 //mprintf(( "************** Camera cut! ************\n" ));
3643 last_Viewer_mode = Viewer_mode;
3644 last_Game_mode = Game_mode;
3646 // Camera moved. Tell stars & debris to not do blurring.
3652 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3653 player_display_packlock_view();
3656 game_set_view_clip();
3658 if (Game_mode & GM_DEAD) {
3659 vector vec_to_deader, view_pos;
3662 Viewer_mode |= VM_DEAD_VIEW;
3664 if (Player_ai->target_objnum != -1) {
3665 int view_from_player = 1;
3667 if (Viewer_mode & VM_OTHER_SHIP) {
3668 // View from target.
3669 Viewer_obj = &Objects[Player_ai->target_objnum];
3671 last_Viewer_objnum = Player_ai->target_objnum;
3673 if ( Viewer_obj->type == OBJ_SHIP ) {
3674 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3675 view_from_player = 0;
3678 last_Viewer_objnum = -1;
3681 if ( view_from_player ) {
3682 // View target from player ship.
3684 *eye_pos = Player_obj->pos;
3685 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3686 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3689 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3691 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3692 dist += flFrametime * 16.0f;
3694 vm_vec_scale(&vec_to_deader, -dist);
3695 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3697 view_pos = Player_obj->pos;
3699 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3700 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3701 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3702 Dead_player_last_vel = Player_obj->phys_info.vel;
3703 //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));
3704 } else if (Player_ai->target_objnum != -1) {
3705 view_pos = Objects[Player_ai->target_objnum].pos;
3707 // Make camera follow explosion, but gradually slow down.
3708 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3709 view_pos = Player_obj->pos;
3710 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3711 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3714 *eye_pos = Dead_camera_pos;
3716 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3718 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3723 // if supernova shockwave
3724 if(supernova_camera_cut()){
3728 // call it dead view
3729 Viewer_mode |= VM_DEAD_VIEW;
3731 // set eye pos and orient
3732 supernova_set_view(eye_pos, eye_orient);
3734 // If already blown up, these other modes can override.
3735 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3736 Viewer_mode &= ~VM_DEAD_VIEW;
3738 Viewer_obj = Player_obj;
3740 if (Viewer_mode & VM_OTHER_SHIP) {
3741 if (Player_ai->target_objnum != -1){
3742 Viewer_obj = &Objects[Player_ai->target_objnum];
3743 last_Viewer_objnum = Player_ai->target_objnum;
3745 Viewer_mode &= ~VM_OTHER_SHIP;
3746 last_Viewer_objnum = -1;
3749 last_Viewer_objnum = -1;
3752 if (Viewer_mode & VM_EXTERNAL) {
3755 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3756 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3758 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3760 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3761 vm_vec_normalize(&eye_dir);
3762 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3765 // Modify the orientation based on head orientation.
3766 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3768 } else if ( Viewer_mode & VM_CHASE ) {
3771 if ( Viewer_obj->phys_info.speed < 0.1 )
3772 move_dir = Viewer_obj->orient.v.fvec;
3774 move_dir = Viewer_obj->phys_info.vel;
3775 vm_vec_normalize(&move_dir);
3778 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3779 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3780 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3781 vm_vec_normalize(&eye_dir);
3783 // JAS: I added the following code because if you slew up using
3784 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3785 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3786 // call because the up and the forward vector are the same. I fixed
3787 // it by adding in a fraction of the right vector all the time to the
3789 vector tmp_up = Viewer_obj->orient.v.uvec;
3790 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3792 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3795 // Modify the orientation based on head orientation.
3796 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3797 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3798 *eye_pos = Camera_pos;
3800 ship * shipp = &Ships[Player_obj->instance];
3802 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3803 vm_vec_normalize(&eye_dir);
3804 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3807 // get an eye position based upon the correct type of object
3808 switch(Viewer_obj->type){
3810 // make a call to get the eye point for the player object
3811 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3814 // make a call to get the eye point for the player object
3815 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3821 #ifdef JOHNS_DEBUG_CODE
3822 john_debug_stuff(&eye_pos, &eye_orient);
3828 apply_hud_shake(eye_orient);
3830 // setup neb2 rendering
3831 neb2_render_setup(eye_pos, eye_orient);
3835 extern void ai_debug_render_stuff();
3838 int Game_subspace_effect = 0;
3839 DCF_BOOL( subspace, Game_subspace_effect );
3841 // Does everything needed to render a frame
3842 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3846 g3_start_frame(game_zbuffer);
3847 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3849 // maybe offset the HUD (jitter stuff)
3850 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3851 HUD_set_offsets(Viewer_obj, !dont_offset);
3853 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3854 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3855 // must be done before ships are rendered
3856 if ( MULTIPLAYER_CLIENT ) {
3857 shield_point_multi_setup();
3860 if ( Game_subspace_effect ) {
3861 stars_draw(0,0,0,1);
3863 stars_draw(1,1,1,0);
3866 obj_render_all(obj_render);
3867 beam_render_all(); // render all beam weapons
3868 particle_render_all(); // render particles after everything else.
3869 trail_render_all(); // render missilie trails after everything else.
3870 mflash_render_all(); // render all muzzle flashes
3872 // Why do we not show the shield effect in these modes? Seems ok.
3873 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3877 // render nebula lightning
3880 // render local player nebula
3881 neb2_render_player();
3884 ai_debug_render_stuff();
3887 #ifndef RELEASE_REAL
3888 // game_framerate_check();
3892 extern void snd_spew_debug_info();
3893 snd_spew_debug_info();
3896 //================ END OF 3D RENDERING STUFF ====================
3900 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3901 hud_maybe_clear_head_area();
3902 anim_render_all(0, flFrametime);
3905 extern int Multi_display_netinfo;
3906 if(Multi_display_netinfo){
3907 extern void multi_display_netinfo();
3908 multi_display_netinfo();
3911 game_tst_frame_pre();
3914 do_timing_test(flFrametime);
3918 extern int OO_update_index;
3919 multi_rate_display(OO_update_index, 375, 0);
3924 extern void oo_display();
3931 //#define JOHNS_DEBUG_CODE 1
3933 #ifdef JOHNS_DEBUG_CODE
3934 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3936 //if ( keyd_pressed[KEY_LSHIFT] )
3938 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3940 model_subsystem *turret = tsys->system_info;
3942 if (turret->type == SUBSYSTEM_TURRET ) {
3943 vector v.fvec, v.uvec;
3944 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3946 ship_model_start(tobj);
3948 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3949 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3950 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3952 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3954 ship_model_stop(tobj);
3964 // following function for dumping frames for purposes of building trailers.
3967 // function to toggle state of dumping every frame into PCX when playing the game
3968 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3972 if ( Debug_dump_frames == 0 ) {
3974 Debug_dump_frames = 15;
3975 Debug_dump_trigger = 0;
3976 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3977 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3980 Debug_dump_frames = 0;
3981 Debug_dump_trigger = 0;
3982 gr_dump_frame_stop();
3983 dc_printf( "Frame dumping is now OFF\n" );
3989 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3993 if ( Debug_dump_frames == 0 ) {
3995 Debug_dump_frames = 15;
3996 Debug_dump_trigger = 1;
3997 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3998 dc_printf( "Frame dumping at 15 hz is now ON\n" );
4001 Debug_dump_frames = 0;
4002 Debug_dump_trigger = 0;
4003 gr_dump_frame_stop();
4004 dc_printf( "Frame dumping is now OFF\n" );
4010 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
4014 if ( Debug_dump_frames == 0 ) {
4016 Debug_dump_frames = 30;
4017 Debug_dump_trigger = 0;
4018 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4019 dc_printf( "Frame dumping at 30 hz is now ON\n" );
4022 Debug_dump_frames = 0;
4023 Debug_dump_trigger = 0;
4024 gr_dump_frame_stop();
4025 dc_printf( "Frame dumping is now OFF\n" );
4031 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
4035 if ( Debug_dump_frames == 0 ) {
4037 Debug_dump_frames = 30;
4038 Debug_dump_trigger = 1;
4039 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
4040 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
4043 Debug_dump_frames = 0;
4044 Debug_dump_trigger = 0;
4045 gr_dump_frame_stop();
4046 dc_printf( "Triggered frame dumping is now OFF\n" );
4052 void game_maybe_dump_frame()
4054 if ( !Debug_dump_frames ){
4058 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
4065 Debug_dump_frame_num++;
4071 extern int Player_dead_state;
4073 // Flip the page and time how long it took.
4074 void game_flip_page_and_time_it()
4079 t1 = timer_get_fixed_seconds();
4081 t2 = timer_get_fixed_seconds();
4084 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
4085 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
4092 void game_simulation_frame()
4094 // blow ships up in multiplayer dogfight
4095 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){
4096 // blow up all non-player ships
4097 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
4100 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
4102 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)){
4103 moveup = GET_NEXT(moveup);
4106 shipp = &Ships[Objects[moveup->objnum].instance];
4107 sip = &Ship_info[shipp->ship_info_index];
4109 // only blow up small ships
4110 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
4111 // function to simply explode a ship where it is currently at
4112 ship_self_destruct( &Objects[moveup->objnum] );
4115 moveup = GET_NEXT(moveup);
4121 // process AWACS stuff - do this first thing
4124 // single player, set Player hits_this_frame to 0
4125 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
4126 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
4127 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
4131 supernova_process();
4132 if(supernova_active() >= 5){
4136 // fire targeting lasers now so that
4137 // 1 - created this frame
4138 // 2 - collide this frame
4139 // 3 - render this frame
4140 // 4 - ignored and deleted next frame
4141 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
4143 ship_process_targeting_lasers();
4145 // do this here so that it works for multiplayer
4147 // get viewer direction
4148 int viewer_direction = PHYSICS_VIEWER_REAR;
4150 if(Viewer_mode == 0){
4151 viewer_direction = PHYSICS_VIEWER_FRONT;
4153 if(Viewer_mode & VM_PADLOCK_UP){
4154 viewer_direction = PHYSICS_VIEWER_UP;
4156 else if(Viewer_mode & VM_PADLOCK_REAR){
4157 viewer_direction = PHYSICS_VIEWER_REAR;
4159 else if(Viewer_mode & VM_PADLOCK_LEFT){
4160 viewer_direction = PHYSICS_VIEWER_LEFT;
4162 else if(Viewer_mode & VM_PADLOCK_RIGHT){
4163 viewer_direction = PHYSICS_VIEWER_RIGHT;
4166 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
4168 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
4171 #define VM_PADLOCK_UP (1 << 7)
4172 #define VM_PADLOCK_REAR (1 << 8)
4173 #define VM_PADLOCK_LEFT (1 << 9)
4174 #define VM_PADLOCK_RIGHT (1 << 10)
4176 // evaluate mission departures and arrivals before we process all objects.
4177 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
4179 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
4180 // ships/wing packets.
4181 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
4182 mission_parse_eval_stuff();
4185 // if we're an observer, move ourselves seperately from the standard physics
4186 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
4187 obj_observer_move(flFrametime);
4190 // move all the objects now
4191 obj_move_all(flFrametime);
4193 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
4194 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
4195 // ship_check_cargo_all();
4196 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4197 mission_eval_goals();
4201 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
4202 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4203 training_check_objectives();
4206 // do all interpolation now
4207 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
4208 // client side processing of warping in effect stages
4209 multi_do_client_warp(flFrametime);
4211 // client side movement of an observer
4212 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
4213 obj_observer_move(flFrametime);
4216 // move all objects - does interpolation now as well
4217 obj_move_all(flFrametime);
4220 // only process the message queue when the player is "in" the game
4221 if ( !Pre_player_entry ){
4222 message_queue_process(); // process any messages send to the player
4225 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4226 message_maybe_distort(); // maybe distort incoming message if comms damaged
4227 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4228 player_process_pending_praise(); // maybe send off a delayed praise message to the player
4229 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4232 if(!(Game_mode & GM_STANDALONE_SERVER)){
4233 // process some stuff every frame (before frame is rendered)
4234 emp_process_local();
4236 hud_update_frame(); // update hud systems
4238 if (!physics_paused) {
4239 // Move particle system
4240 particle_move_all(flFrametime);
4242 // Move missile trails
4243 trail_move_all(flFrametime);
4245 // process muzzle flashes
4246 mflash_process_all();
4248 // Flash the gun flashes
4249 shipfx_flash_do_frame(flFrametime);
4251 shockwave_move_all(flFrametime); // update all the shockwaves
4254 // subspace missile strikes
4257 obj_snd_do_frame(); // update the object-linked persistant sounds
4258 game_maybe_update_sound_environment();
4259 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4261 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4263 if ( Game_subspace_effect ) {
4264 game_start_subspace_ambient_sound();
4270 // Maybe render and process the dead-popup
4271 void game_maybe_do_dead_popup(float frametime)
4273 if ( popupdead_is_active() ) {
4275 int choice = popupdead_do_frame(frametime);
4277 if ( Game_mode & GM_NORMAL ) {
4281 if(game_do_cd_mission_check(Game_current_mission_filename)){
4282 gameseq_post_event(GS_EVENT_ENTER_GAME);
4284 gameseq_post_event(GS_EVENT_MAIN_MENU);
4289 gameseq_post_event(GS_EVENT_END_GAME);
4294 if(game_do_cd_mission_check(Game_current_mission_filename)){
4295 gameseq_post_event(GS_EVENT_START_GAME);
4297 gameseq_post_event(GS_EVENT_MAIN_MENU);
4301 // this should only happen during a red alert mission
4304 Assert(The_mission.red_alert);
4305 if(!The_mission.red_alert){
4307 if(game_do_cd_mission_check(Game_current_mission_filename)){
4308 gameseq_post_event(GS_EVENT_START_GAME);
4310 gameseq_post_event(GS_EVENT_MAIN_MENU);
4315 // choose the previous mission
4316 mission_campaign_previous_mission();
4318 if(game_do_cd_mission_check(Game_current_mission_filename)){
4319 gameseq_post_event(GS_EVENT_START_GAME);
4321 gameseq_post_event(GS_EVENT_MAIN_MENU);
4332 case POPUPDEAD_DO_MAIN_HALL:
4333 multi_quit_game(PROMPT_NONE,-1);
4336 case POPUPDEAD_DO_RESPAWN:
4337 multi_respawn_normal();
4338 event_music_player_respawn();
4341 case POPUPDEAD_DO_OBSERVER:
4342 multi_respawn_observer();
4343 event_music_player_respawn_as_observer();
4352 if ( leave_popup ) {
4358 // returns true if player is actually in a game_play stats
4359 int game_actually_playing()
4363 state = gameseq_get_state();
4364 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4370 // Draw the 2D HUD gauges
4371 void game_render_hud_2d()
4373 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4377 HUD_render_2d(flFrametime);
4381 // Draw the 3D-dependant HUD gauges
4382 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4384 g3_start_frame(0); // 0 = turn zbuffering off
4385 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4387 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4388 HUD_render_3d(flFrametime);
4392 game_sunspot_process(flFrametime);
4394 // Diminish the palette effect
4395 game_flash_diminish(flFrametime);
4403 int actually_playing;
4404 fix total_time1, total_time2;
4405 fix render2_time1=0, render2_time2=0;
4406 fix render3_time1=0, render3_time2=0;
4407 fix flip_time1=0, flip_time2=0;
4408 fix clear_time1=0, clear_time2=0;
4414 if (Framerate_delay) {
4415 int start_time = timer_get_milliseconds();
4416 while (timer_get_milliseconds() < start_time + Framerate_delay)
4422 demo_do_frame_start();
4424 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4429 // start timing frame
4430 timing_frame_start();
4432 total_time1 = timer_get_fixed_seconds();
4434 // var to hold which state we are in
4435 actually_playing = game_actually_playing();
4437 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4438 if (!(Game_mode & GM_STANDALONE_SERVER)){
4439 Assert( OBJ_INDEX(Player_obj) >= 0 );
4443 if (Missiontime > Entry_delay_time){
4444 Pre_player_entry = 0;
4446 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4449 // Note: These are done even before the player enters, else buffers can overflow.
4450 if (! (Game_mode & GM_STANDALONE_SERVER)){
4454 shield_frame_init();
4456 if ( Player->control_mode != PCM_NORMAL )
4459 if ( !Pre_player_entry && actually_playing ) {
4460 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4462 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4463 game_process_keys();
4465 // don't read flying controls if we're playing a demo back
4466 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4467 read_player_controls( Player_obj, flFrametime);
4471 // if we're not the master, we may have to send the server-critical ship status button_info bits
4472 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4473 multi_maybe_send_ship_status();
4478 // Reset the whack stuff
4481 // These two lines must be outside of Pre_player_entry code,
4482 // otherwise too many lights are added.
4485 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4489 game_simulation_frame();
4491 // if not actually in a game play state, then return. This condition could only be true in
4492 // a multiplayer game.
4493 if ( !actually_playing ) {
4494 Assert( Game_mode & GM_MULTIPLAYER );
4498 if (!Pre_player_entry) {
4499 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4500 clear_time1 = timer_get_fixed_seconds();
4501 // clear the screen to black
4503 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4507 clear_time2 = timer_get_fixed_seconds();
4508 render3_time1 = timer_get_fixed_seconds();
4509 game_render_frame_setup(&eye_pos, &eye_orient);
4510 game_render_frame( &eye_pos, &eye_orient );
4512 // save the eye position and orientation
4513 if ( Game_mode & GM_MULTIPLAYER ) {
4514 Net_player->s_info.eye_pos = eye_pos;
4515 Net_player->s_info.eye_orient = eye_orient;
4518 hud_show_target_model();
4520 // check to see if we should display the death died popup
4521 if(Game_mode & GM_DEAD_BLEW_UP){
4522 if(Game_mode & GM_MULTIPLAYER){
4523 // catch the situation where we're supposed to be warping out on this transition
4524 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4525 gameseq_post_event(GS_EVENT_DEBRIEF);
4526 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4527 Player_died_popup_wait = -1;
4531 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4532 Player_died_popup_wait = -1;
4538 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4539 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4540 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4541 if(!popupdead_is_active()){
4545 Player_multi_died_check = -1;
4549 render3_time2 = timer_get_fixed_seconds();
4550 render2_time1 = timer_get_fixed_seconds();
4553 game_get_framerate();
4554 game_show_framerate();
4556 game_show_time_left();
4558 // Draw the 2D HUD gauges
4559 if(supernova_active() < 3){
4560 game_render_hud_2d();
4563 game_set_view_clip();
4565 // Draw 3D HUD gauges
4566 game_render_hud_3d(&eye_pos, &eye_orient);
4570 render2_time2 = timer_get_fixed_seconds();
4572 // maybe render and process the dead popup
4573 game_maybe_do_dead_popup(flFrametime);
4575 // start timing frame
4576 timing_frame_stop();
4577 // timing_display(30, 10);
4579 // If a regular popup is active, don't flip (popup code flips)
4580 if( !popup_running_state() ){
4581 flip_time1 = timer_get_fixed_seconds();
4582 game_flip_page_and_time_it();
4583 flip_time2 = timer_get_fixed_seconds();
4587 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4590 game_show_standalone_framerate();
4594 game_do_training_checks();
4597 // process lightning (nebula only)
4600 total_time2 = timer_get_fixed_seconds();
4602 // Got some timing numbers
4603 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4604 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4605 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4606 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4607 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4610 demo_do_frame_end();
4612 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4618 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4619 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4620 // died. This resulted in screwed up death sequences.
4622 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4623 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4624 static int timer_paused=0;
4625 #if defined(TIMER_TEST) && !defined(NDEBUG)
4626 static int stop_count,start_count;
4627 static int time_stopped,time_started;
4629 int saved_timestamp_ticker = -1;
4631 void game_reset_time()
4633 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4637 // Last_time = timer_get_fixed_seconds();
4643 void game_stop_time()
4645 if (timer_paused==0) {
4647 time = timer_get_fixed_seconds();
4648 // Save how much time progressed so far in the frame so we can
4649 // use it when we unpause.
4650 Last_delta_time = time - Last_time;
4652 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4653 if (Last_delta_time < 0) {
4654 #if defined(TIMER_TEST) && !defined(NDEBUG)
4655 Int3(); //get Matt!!!!
4657 Last_delta_time = 0;
4659 #if defined(TIMER_TEST) && !defined(NDEBUG)
4660 time_stopped = time;
4663 // Stop the timer_tick stuff...
4664 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4665 saved_timestamp_ticker = timestamp_ticker;
4669 #if defined(TIMER_TEST) && !defined(NDEBUG)
4674 void game_start_time()
4677 Assert(timer_paused >= 0);
4678 if (timer_paused==0) {
4680 time = timer_get_fixed_seconds();
4681 #if defined(TIMER_TEST) && !defined(NDEBUG)
4683 Int3(); //get Matt!!!!
4686 // Take current time, and set it backwards to account for time
4687 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4688 // will be correct when it goes to calculate the frametime next
4690 Last_time = time - Last_delta_time;
4691 #if defined(TIMER_TEST) && !defined(NDEBUG)
4692 time_started = time;
4695 // Restore the timer_tick stuff...
4696 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4697 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4698 timestamp_ticker = saved_timestamp_ticker;
4699 saved_timestamp_ticker = -1;
4702 #if defined(TIMER_TEST) && !defined(NDEBUG)
4708 void game_set_frametime(int state)
4711 float frame_cap_diff;
4713 thistime = timer_get_fixed_seconds();
4715 if ( Last_time == 0 )
4716 Frametime = F1_0 / 30;
4718 Frametime = thistime - Last_time;
4720 // Frametime = F1_0 / 30;
4722 fix debug_frametime = Frametime; // Just used to display frametime.
4724 // If player hasn't entered mission yet, make frame take 1/4 second.
4725 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4728 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4730 fix frame_speed = F1_0 / Debug_dump_frames;
4732 if (Frametime > frame_speed ){
4733 nprintf(("warning","slow frame: %x\n",Frametime));
4736 thistime = timer_get_fixed_seconds();
4737 Frametime = thistime - Last_time;
4738 } while (Frametime < frame_speed );
4740 Frametime = frame_speed;
4744 Assert( Framerate_cap > 0 );
4746 // Cap the framerate so it doesn't get too high.
4750 cap = F1_0/Framerate_cap;
4751 if (Frametime < cap) {
4752 thistime = cap - Frametime;
4753 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4754 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4756 thistime = timer_get_fixed_seconds();
4760 if((Game_mode & GM_STANDALONE_SERVER) &&
4761 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4763 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4764 Sleep((DWORD)(frame_cap_diff*1000));
4766 thistime += fl2f((frame_cap_diff));
4768 Frametime = thistime - Last_time;
4771 // If framerate is too low, cap it.
4772 if (Frametime > MAX_FRAMETIME) {
4774 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4776 // to remove warnings in release build
4777 debug_frametime = fl2f(flFrametime);
4779 Frametime = MAX_FRAMETIME;
4782 Frametime = fixmul(Frametime, Game_time_compression);
4784 Last_time = thistime;
4785 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4787 flFrametime = f2fl(Frametime);
4788 //if(!(Game_mode & GM_PLAYING_DEMO)){
4789 timestamp_inc(flFrametime);
4791 /* if ((Framecount > 0) && (Framecount < 10)) {
4792 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4797 // This is called from game_do_frame(), and from navmap_do_frame()
4798 void game_update_missiontime()
4800 // TODO JAS: Put in if and move this into game_set_frametime,
4801 // fix navmap to call game_stop/start_time
4802 //if ( !timer_paused )
4803 Missiontime += Frametime;
4806 void game_do_frame()
4808 game_set_frametime(GS_STATE_GAME_PLAY);
4809 game_update_missiontime();
4811 if (Game_mode & GM_STANDALONE_SERVER) {
4812 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4815 if ( game_single_step && (last_single_step == game_single_step) ) {
4816 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4817 while( key_checkch() == 0 )
4819 os_set_title( XSTR( "FreeSpace", 171) );
4820 Last_time = timer_get_fixed_seconds();
4823 last_single_step = game_single_step;
4825 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4826 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4830 Keep_mouse_centered = 0;
4831 monitor_update(); // Update monitor variables
4834 void multi_maybe_do_frame()
4836 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4841 int Joymouse_button_status = 0;
4843 // Flush all input devices
4851 Joymouse_button_status = 0;
4853 //mprintf(("Game flush!\n" ));
4856 // function for multiplayer only which calls game_do_state_common() when running the
4858 void game_do_dc_networking()
4860 Assert( Game_mode & GM_MULTIPLAYER );
4862 game_do_state_common( gameseq_get_state() );
4865 // Call this whenever in a loop, or when you need to check for a keystroke.
4866 int game_check_key()
4872 // convert keypad enter to normal enter
4873 if ((k & KEY_MASK) == KEY_PADENTER)
4874 k = (k & ~KEY_MASK) | KEY_ENTER;
4879 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4881 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4882 static int Demo_show_trailer_timestamp = 0;
4884 void demo_reset_trailer_timer()
4886 Demo_show_trailer_timestamp = timer_get_milliseconds();
4889 void demo_maybe_show_trailer(int k)
4892 // if key pressed, reset demo trailer timer
4894 demo_reset_trailer_timer();
4898 // if mouse moved, reset demo trailer timer
4901 mouse_get_delta(&dx, &dy);
4902 if ( (dx > 0) || (dy > 0) ) {
4903 demo_reset_trailer_timer();
4907 // if joystick has moved, reset demo trailer timer
4910 joy_get_delta(&dx, &dy);
4911 if ( (dx > 0) || (dy > 0) ) {
4912 demo_reset_trailer_timer();
4916 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4917 // the low-level code. Ugly, I know... but was the simplest and most
4920 // if 30 seconds since last demo trailer time reset, launch movie
4921 if ( os_foreground() ) {
4922 int now = timer_get_milliseconds();
4923 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4924 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4926 movie_play( NOX("fstrailer2.mve") );
4927 demo_reset_trailer_timer();
4935 // same as game_check_key(), except this is used while actually in the game. Since there
4936 // generally are differences between game control keys and general UI keys, makes sense to
4937 // have seperate functions for each case. If you are not checking a game control while in a
4938 // mission, you should probably be using game_check_key() instead.
4943 if (!os_foreground()) {
4948 // If we're in a single player game, pause it.
4949 if (!(Game_mode & GM_MULTIPLAYER)){
4950 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4951 game_process_pause_key();
4958 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4959 demo_maybe_show_trailer(k);
4962 // Move the mouse cursor with the joystick.
4963 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4964 // Move the mouse cursor with the joystick
4968 joy_get_pos( &jx, &jy, &jz, &jr );
4970 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4971 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4974 mouse_get_real_pos( &mx, &my );
4975 mouse_set_pos( mx+dx, my+dy );
4980 m = mouse_down(MOUSE_LEFT_BUTTON);
4982 if ( j != Joymouse_button_status ) {
4983 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4984 Joymouse_button_status = j;
4986 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4987 } else if ( (!j) && (m) ) {
4988 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4993 // if we should be ignoring keys because of some multiplayer situations
4994 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4998 // If a popup is running, don't process all the Fn keys
4999 if( popup_active() ) {
5003 state = gameseq_get_state();
5005 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
5008 case KEY_DEBUGGED + KEY_BACKSP:
5013 launch_context_help();
5018 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
5020 // don't allow f2 while warping out in multiplayer
5021 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
5026 case GS_STATE_INITIAL_PLAYER_SELECT:
5027 case GS_STATE_OPTIONS_MENU:
5028 case GS_STATE_HUD_CONFIG:
5029 case GS_STATE_CONTROL_CONFIG:
5030 case GS_STATE_DEATH_DIED:
5031 case GS_STATE_DEATH_BLEW_UP:
5032 case GS_STATE_VIEW_MEDALS:
5036 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
5043 // hotkey selection screen -- only valid from briefing and beyond.
5045 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
5046 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) ) {
5047 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
5053 case KEY_DEBUGGED + KEY_F3:
5054 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
5057 case KEY_DEBUGGED + KEY_F4:
5058 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
5062 if(Game_mode & GM_MULTIPLAYER){
5063 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
5064 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5068 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
5069 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
5075 case KEY_ESC | KEY_SHIFTED:
5076 // make sure to quit properly out of multiplayer
5077 if(Game_mode & GM_MULTIPLAYER){
5078 multi_quit_game(PROMPT_NONE);
5081 gameseq_post_event( GS_EVENT_QUIT_GAME );
5086 case KEY_DEBUGGED + KEY_P:
5089 case KEY_PRINT_SCRN:
5091 static int counter = 0;
5096 sprintf( tmp_name, NOX("screen%02d"), counter );
5098 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
5099 gr_print_screen(tmp_name);
5107 case KEY_SHIFTED | KEY_ENTER: {
5109 #if !defined(NDEBUG)
5111 if ( Game_mode & GM_NORMAL ){
5115 // if we're in multiplayer mode, do some special networking
5116 if(Game_mode & GM_MULTIPLAYER){
5117 debug_console(game_do_dc_networking);
5124 if ( Game_mode & GM_NORMAL )
5138 gameseq_post_event(GS_EVENT_QUIT_GAME);
5141 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
5144 void camera_set_position( vector *pos )
5149 void camera_set_orient( matrix *orient )
5151 Camera_orient = *orient;
5154 void camera_set_velocity( vector *vel, int instantaneous )
5156 Camera_desired_velocity.xyz.x = 0.0f;
5157 Camera_desired_velocity.xyz.y = 0.0f;
5158 Camera_desired_velocity.xyz.z = 0.0f;
5160 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
5161 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
5162 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
5164 if ( instantaneous ) {
5165 Camera_velocity = Camera_desired_velocity;
5173 vector new_vel, delta_pos;
5175 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
5176 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
5177 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
5179 Camera_velocity = new_vel;
5181 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
5183 vm_vec_add2( &Camera_pos, &delta_pos );
5185 float ot = Camera_time+0.0f;
5187 Camera_time += flFrametime;
5189 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
5192 tmp.xyz.z = 4.739f; // always go this fast forward.
5194 // pick x and y velocities so they are always on a
5195 // circle with a 25 m radius.
5197 float tmp_angle = frand()*PI2;
5199 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
5200 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
5202 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
5204 //mprintf(( "Changing velocity!\n" ));
5205 camera_set_velocity( &tmp, 0 );
5208 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
5209 vector tmp = { 0.0f, 0.0f, 0.0f };
5210 camera_set_velocity( &tmp, 0 );
5215 void end_demo_campaign_do()
5217 #if defined(FS2_DEMO) || defined(FS1_DEMO)
5218 // show upsell screens
5219 demo_upsell_show_screens();
5220 #elif defined(OEM_BUILD)
5221 // show oem upsell screens
5222 oem_upsell_show_screens();
5225 // drop into main hall
5226 gameseq_post_event( GS_EVENT_MAIN_MENU );
5229 // All code to process events. This is the only place
5230 // that you should change the state of the game.
5231 void game_process_event( int current_state, int event )
5233 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5236 case GS_EVENT_SIMULATOR_ROOM:
5237 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5240 case GS_EVENT_MAIN_MENU:
5241 gameseq_set_state(GS_STATE_MAIN_MENU);
5244 case GS_EVENT_OPTIONS_MENU:
5245 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5248 case GS_EVENT_BARRACKS_MENU:
5249 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5252 case GS_EVENT_TECH_MENU:
5253 gameseq_set_state(GS_STATE_TECH_MENU);
5256 case GS_EVENT_TRAINING_MENU:
5257 gameseq_set_state(GS_STATE_TRAINING_MENU);
5260 case GS_EVENT_START_GAME:
5261 Select_default_ship = 0;
5262 Player_multi_died_check = -1;
5263 gameseq_set_state(GS_STATE_CMD_BRIEF);
5266 case GS_EVENT_START_BRIEFING:
5267 gameseq_set_state(GS_STATE_BRIEFING);
5270 case GS_EVENT_DEBRIEF:
5271 // did we end the campaign in the main freespace 2 single player campaign?
5273 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace")) {
5275 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5277 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5279 gameseq_set_state(GS_STATE_DEBRIEF);
5282 Player_multi_died_check = -1;
5285 case GS_EVENT_SHIP_SELECTION:
5286 gameseq_set_state( GS_STATE_SHIP_SELECT );
5289 case GS_EVENT_WEAPON_SELECTION:
5290 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5293 case GS_EVENT_ENTER_GAME:
5295 // maybe start recording a demo
5297 demo_start_record("test.fsd");
5301 if (Game_mode & GM_MULTIPLAYER) {
5302 // if we're respawning, make sure we change the view mode so that the hud shows up
5303 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5307 gameseq_set_state(GS_STATE_GAME_PLAY);
5309 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5312 Player_multi_died_check = -1;
5314 // clear multiplayer button info
5315 extern button_info Multi_ship_status_bi;
5316 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5318 Start_time = f2fl(timer_get_approx_seconds());
5320 mprintf(("Entering game at time = %7.3f\n", Start_time));
5324 case GS_EVENT_START_GAME_QUICK:
5325 Select_default_ship = 1;
5326 gameseq_post_event(GS_EVENT_ENTER_GAME);
5330 case GS_EVENT_END_GAME:
5331 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5332 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5333 gameseq_set_state(GS_STATE_MAIN_MENU);
5338 Player_multi_died_check = -1;
5341 case GS_EVENT_QUIT_GAME:
5342 main_hall_stop_music();
5343 main_hall_stop_ambient();
5344 gameseq_set_state(GS_STATE_QUIT_GAME);
5346 Player_multi_died_check = -1;
5349 case GS_EVENT_GAMEPLAY_HELP:
5350 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5353 case GS_EVENT_PAUSE_GAME:
5354 gameseq_push_state(GS_STATE_GAME_PAUSED);
5357 case GS_EVENT_DEBUG_PAUSE_GAME:
5358 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5361 case GS_EVENT_TRAINING_PAUSE:
5362 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5365 case GS_EVENT_PREVIOUS_STATE:
5366 gameseq_pop_state();
5369 case GS_EVENT_TOGGLE_FULLSCREEN:
5370 #ifndef HARDWARE_ONLY
5372 if ( gr_screen.mode == GR_SOFTWARE ) {
5373 gr_init( GR_640, GR_DIRECTDRAW );
5374 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5375 gr_init( GR_640, GR_SOFTWARE );
5381 case GS_EVENT_TOGGLE_GLIDE:
5383 if ( gr_screen.mode != GR_GLIDE ) {
5384 gr_init( GR_640, GR_GLIDE );
5386 gr_init( GR_640, GR_SOFTWARE );
5391 case GS_EVENT_LOAD_MISSION_MENU:
5392 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5395 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5396 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5399 case GS_EVENT_HUD_CONFIG:
5400 gameseq_push_state( GS_STATE_HUD_CONFIG );
5403 case GS_EVENT_CONTROL_CONFIG:
5404 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5407 case GS_EVENT_DEATH_DIED:
5408 gameseq_set_state( GS_STATE_DEATH_DIED );
5411 case GS_EVENT_DEATH_BLEW_UP:
5412 if ( current_state == GS_STATE_DEATH_DIED ) {
5413 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5414 event_music_player_death();
5416 // multiplayer clients set their extra check here
5417 if(Game_mode & GM_MULTIPLAYER){
5418 // set the multi died absolute last chance check
5419 Player_multi_died_check = time(NULL);
5422 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5426 case GS_EVENT_NEW_CAMPAIGN:
5427 if (!mission_load_up_campaign()){
5428 readyroom_continue_campaign();
5431 Player_multi_died_check = -1;
5434 case GS_EVENT_CAMPAIGN_CHEAT:
5435 if (!mission_load_up_campaign()){
5437 // bash campaign value
5438 extern char Main_hall_campaign_cheat[512];
5441 // look for the mission
5442 for(idx=0; idx<Campaign.num_missions; idx++){
5443 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5444 Campaign.next_mission = idx;
5445 Campaign.prev_mission = idx - 1;
5452 readyroom_continue_campaign();
5455 Player_multi_died_check = -1;
5458 case GS_EVENT_CAMPAIGN_ROOM:
5459 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5462 case GS_EVENT_CMD_BRIEF:
5463 gameseq_set_state(GS_STATE_CMD_BRIEF);
5466 case GS_EVENT_RED_ALERT:
5467 gameseq_set_state(GS_STATE_RED_ALERT);
5470 case GS_EVENT_CREDITS:
5471 gameseq_set_state( GS_STATE_CREDITS );
5474 case GS_EVENT_VIEW_MEDALS:
5475 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5478 case GS_EVENT_SHOW_GOALS:
5479 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5482 case GS_EVENT_HOTKEY_SCREEN:
5483 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5486 // multiplayer stuff follow these comments
5488 case GS_EVENT_MULTI_JOIN_GAME:
5489 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5492 case GS_EVENT_MULTI_HOST_SETUP:
5493 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5496 case GS_EVENT_MULTI_CLIENT_SETUP:
5497 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5500 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5501 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5504 case GS_EVENT_MULTI_STD_WAIT:
5505 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5508 case GS_EVENT_STANDALONE_MAIN:
5509 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5512 case GS_EVENT_MULTI_PAUSE:
5513 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5516 case GS_EVENT_INGAME_PRE_JOIN:
5517 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5520 case GS_EVENT_EVENT_DEBUG:
5521 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5524 // Start a warpout where player automatically goes 70 no matter what
5525 // and can't cancel out of it.
5526 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5527 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5529 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5530 Player->saved_viewer_mode = Viewer_mode;
5531 Player->control_mode = PCM_WARPOUT_STAGE1;
5532 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5533 Warpout_time = 0.0f; // Start timer!
5536 case GS_EVENT_PLAYER_WARPOUT_START:
5537 if ( Player->control_mode != PCM_NORMAL ) {
5538 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5540 Player->saved_viewer_mode = Viewer_mode;
5541 Player->control_mode = PCM_WARPOUT_STAGE1;
5542 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5543 Warpout_time = 0.0f; // Start timer!
5544 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5548 case GS_EVENT_PLAYER_WARPOUT_STOP:
5549 if ( Player->control_mode != PCM_NORMAL ) {
5550 if ( !Warpout_forced ) { // cannot cancel forced warpout
5551 Player->control_mode = PCM_NORMAL;
5552 Viewer_mode = Player->saved_viewer_mode;
5553 hud_subspace_notify_abort();
5554 mprintf(( "Player put back to normal mode.\n" ));
5555 if ( Warpout_sound > -1 ) {
5556 snd_stop( Warpout_sound );
5563 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5564 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5565 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5566 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5568 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5569 shipfx_warpout_start( Player_obj );
5570 Player->control_mode = PCM_WARPOUT_STAGE2;
5571 Player->saved_viewer_mode = Viewer_mode;
5572 Viewer_mode |= VM_WARP_CHASE;
5574 vector tmp = Player_obj->pos;
5576 ship_get_eye( &tmp, &tmp_m, Player_obj );
5577 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5578 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5579 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5581 camera_set_position( &tmp );
5582 camera_set_orient( &Player_obj->orient );
5583 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5585 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5586 camera_set_velocity( &tmp_vel, 1);
5590 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5591 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5592 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5593 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5595 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5596 Player->control_mode = PCM_WARPOUT_STAGE3;
5600 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5601 mprintf(( "Player warped out. Going to debriefing!\n" ));
5602 Player->control_mode = PCM_NORMAL;
5603 Viewer_mode = Player->saved_viewer_mode;
5606 // we have a special debriefing screen for multiplayer furballs
5607 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5608 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5610 // do the normal debriefing for all other situations
5612 gameseq_post_event(GS_EVENT_DEBRIEF);
5616 case GS_EVENT_STANDALONE_POSTGAME:
5617 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5620 case GS_EVENT_INITIAL_PLAYER_SELECT:
5621 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5624 case GS_EVENT_GAME_INIT:
5625 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5626 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5628 // see if the command line option has been set to use the last pilot, and act acoordingly
5629 if( player_select_get_last_pilot() ) {
5630 // always enter the main menu -- do the automatic network startup stuff elsewhere
5631 // so that we still have valid checks for networking modes, etc.
5632 gameseq_set_state(GS_STATE_MAIN_MENU);
5634 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5639 case GS_EVENT_MULTI_MISSION_SYNC:
5640 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5643 case GS_EVENT_MULTI_START_GAME:
5644 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5647 case GS_EVENT_MULTI_HOST_OPTIONS:
5648 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5651 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5652 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5655 case GS_EVENT_TEAM_SELECT:
5656 gameseq_set_state(GS_STATE_TEAM_SELECT);
5659 case GS_EVENT_END_CAMPAIGN:
5660 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5663 case GS_EVENT_END_DEMO:
5664 gameseq_set_state(GS_STATE_END_DEMO);
5667 case GS_EVENT_LOOP_BRIEF:
5668 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5677 // Called when a state is being left.
5678 // The current state is still at old_state, but as soon as
5679 // this function leaves, then the current state will become
5680 // new state. You should never try to change the state
5681 // in here... if you think you need to, you probably really
5682 // need to post an event, not change the state.
5683 void game_leave_state( int old_state, int new_state )
5685 int end_mission = 1;
5687 switch (new_state) {
5688 case GS_STATE_GAME_PAUSED:
5689 case GS_STATE_DEBUG_PAUSED:
5690 case GS_STATE_OPTIONS_MENU:
5691 case GS_STATE_CONTROL_CONFIG:
5692 case GS_STATE_MISSION_LOG_SCROLLBACK:
5693 case GS_STATE_DEATH_DIED:
5694 case GS_STATE_SHOW_GOALS:
5695 case GS_STATE_HOTKEY_SCREEN:
5696 case GS_STATE_MULTI_PAUSED:
5697 case GS_STATE_TRAINING_PAUSED:
5698 case GS_STATE_EVENT_DEBUG:
5699 case GS_STATE_GAMEPLAY_HELP:
5700 end_mission = 0; // these events shouldn't end a mission
5704 switch (old_state) {
5705 case GS_STATE_BRIEFING:
5706 brief_stop_voices();
5707 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5708 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5709 && (new_state != GS_STATE_TEAM_SELECT) ){
5710 common_select_close();
5711 if ( new_state == GS_STATE_MAIN_MENU ) {
5712 freespace_stop_mission();
5716 // COMMAND LINE OPTION
5717 if (Cmdline_multi_stream_chat_to_file){
5718 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5719 cfclose(Multi_chat_stream);
5723 case GS_STATE_DEBRIEF:
5724 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5729 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5730 multi_df_debrief_close();
5733 case GS_STATE_LOAD_MISSION_MENU:
5734 mission_load_menu_close();
5737 case GS_STATE_SIMULATOR_ROOM:
5741 case GS_STATE_CAMPAIGN_ROOM:
5742 campaign_room_close();
5745 case GS_STATE_CMD_BRIEF:
5746 if (new_state == GS_STATE_OPTIONS_MENU) {
5751 if (new_state == GS_STATE_MAIN_MENU)
5752 freespace_stop_mission();
5757 case GS_STATE_RED_ALERT:
5761 case GS_STATE_SHIP_SELECT:
5762 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5763 new_state != GS_STATE_HOTKEY_SCREEN &&
5764 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5765 common_select_close();
5766 if ( new_state == GS_STATE_MAIN_MENU ) {
5767 freespace_stop_mission();
5772 case GS_STATE_WEAPON_SELECT:
5773 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5774 new_state != GS_STATE_HOTKEY_SCREEN &&
5775 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5776 common_select_close();
5777 if ( new_state == GS_STATE_MAIN_MENU ) {
5778 freespace_stop_mission();
5783 case GS_STATE_TEAM_SELECT:
5784 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5785 new_state != GS_STATE_HOTKEY_SCREEN &&
5786 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5787 common_select_close();
5788 if ( new_state == GS_STATE_MAIN_MENU ) {
5789 freespace_stop_mission();
5794 case GS_STATE_MAIN_MENU:
5795 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5802 case GS_STATE_OPTIONS_MENU:
5803 //game_start_time();
5804 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5805 multi_join_clear_game_list();
5807 options_menu_close();
5810 case GS_STATE_BARRACKS_MENU:
5811 if(new_state != GS_STATE_VIEW_MEDALS){
5816 case GS_STATE_MISSION_LOG_SCROLLBACK:
5817 hud_scrollback_close();
5820 case GS_STATE_TRAINING_MENU:
5821 training_menu_close();
5824 case GS_STATE_GAME_PLAY:
5825 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5826 player_save_target_and_weapon_link_prefs();
5827 game_stop_looped_sounds();
5830 sound_env_disable();
5831 joy_ff_stop_effects();
5833 // stop game time under certain conditions
5834 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5839 // shut down any recording or playing demos
5844 // when in multiplayer and going back to the main menu, send a leave game packet
5845 // right away (before calling stop mission). stop_mission was taking to long to
5846 // close mission down and I want people to get notified ASAP.
5847 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5848 multi_quit_game(PROMPT_NONE);
5851 freespace_stop_mission();
5852 Game_time_compression = F1_0;
5856 case GS_STATE_TECH_MENU:
5860 case GS_STATE_TRAINING_PAUSED:
5861 Training_num_lines = 0;
5862 // fall through to GS_STATE_GAME_PAUSED
5864 case GS_STATE_GAME_PAUSED:
5866 if ( end_mission ) {
5871 case GS_STATE_DEBUG_PAUSED:
5874 pause_debug_close();
5878 case GS_STATE_HUD_CONFIG:
5882 // join/start a game
5883 case GS_STATE_MULTI_JOIN_GAME:
5884 if(new_state != GS_STATE_OPTIONS_MENU){
5885 multi_join_game_close();
5889 case GS_STATE_MULTI_HOST_SETUP:
5890 case GS_STATE_MULTI_CLIENT_SETUP:
5891 // if this is just the host going into the options screen, don't do anything
5892 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5896 // close down the proper state
5897 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5898 multi_create_game_close();
5900 multi_game_client_setup_close();
5903 // COMMAND LINE OPTION
5904 if (Cmdline_multi_stream_chat_to_file){
5905 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5906 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5907 cfclose(Multi_chat_stream);
5912 case GS_STATE_CONTROL_CONFIG:
5913 control_config_close();
5916 case GS_STATE_DEATH_DIED:
5917 Game_mode &= ~GM_DEAD_DIED;
5919 // early end while respawning or blowing up in a multiplayer game
5920 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5922 freespace_stop_mission();
5926 case GS_STATE_DEATH_BLEW_UP:
5927 Game_mode &= ~GM_DEAD_BLEW_UP;
5929 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5930 // to determine if I should do anything.
5931 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5933 freespace_stop_mission();
5936 // if we are not respawing as an observer or as a player, our new state will not
5937 // be gameplay state.
5938 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5939 game_stop_time(); // hasn't been called yet!!
5940 freespace_stop_mission();
5946 case GS_STATE_CREDITS:
5950 case GS_STATE_VIEW_MEDALS:
5954 case GS_STATE_SHOW_GOALS:
5955 mission_show_goals_close();
5958 case GS_STATE_HOTKEY_SCREEN:
5959 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5960 mission_hotkey_close();
5964 case GS_STATE_MULTI_MISSION_SYNC:
5965 // if we're moving into the options menu, don't do anything
5966 if(new_state == GS_STATE_OPTIONS_MENU){
5970 Assert( Game_mode & GM_MULTIPLAYER );
5972 if ( new_state == GS_STATE_GAME_PLAY ){
5973 // palette_restore_palette();
5975 // change a couple of flags to indicate our state!!!
5976 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5977 send_netplayer_update_packet();
5979 // set the game mode
5980 Game_mode |= GM_IN_MISSION;
5984 case GS_STATE_VIEW_CUTSCENES:
5985 cutscenes_screen_close();
5988 case GS_STATE_MULTI_STD_WAIT:
5989 multi_standalone_wait_close();
5992 case GS_STATE_STANDALONE_MAIN:
5993 standalone_main_close();
5994 if(new_state == GS_STATE_MULTI_STD_WAIT){
5995 init_multiplayer_stats();
5999 case GS_STATE_MULTI_PAUSED:
6000 // if ( end_mission ){
6005 case GS_STATE_INGAME_PRE_JOIN:
6006 multi_ingame_select_close();
6009 case GS_STATE_STANDALONE_POSTGAME:
6010 multi_standalone_postgame_close();
6013 case GS_STATE_INITIAL_PLAYER_SELECT:
6014 player_select_close();
6017 case GS_STATE_MULTI_START_GAME:
6018 multi_start_game_close();
6021 case GS_STATE_MULTI_HOST_OPTIONS:
6022 multi_host_options_close();
6025 case GS_STATE_END_OF_CAMPAIGN:
6026 mission_campaign_end_close();
6029 case GS_STATE_LOOP_BRIEF:
6035 // Called when a state is being entered.
6036 // The current state is set to the state we're entering at
6037 // this point, and old_state is set to the state we're coming
6038 // from. You should never try to change the state
6039 // in here... if you think you need to, you probably really
6040 // need to post an event, not change the state.
6042 void game_enter_state( int old_state, int new_state )
6044 switch (new_state) {
6045 case GS_STATE_MAIN_MENU:
6046 // in multiplayer mode, be sure that we are not doing networking anymore.
6047 if ( Game_mode & GM_MULTIPLAYER ) {
6048 Assert( Net_player != NULL );
6049 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
6052 Game_time_compression = F1_0;
6054 // determine which ship this guy is currently based on
6055 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6058 if (Player->on_bastion) {
6066 case GS_STATE_BRIEFING:
6067 main_hall_stop_music();
6068 main_hall_stop_ambient();
6070 if (Game_mode & GM_NORMAL) {
6071 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6072 // MWA: or from options or hotkey screens
6073 // JH: or if the command brief state already did this
6074 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6075 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
6076 && (old_state != GS_STATE_CMD_BRIEF) ) {
6077 if ( !game_start_mission() ) // this should put us into a new state on failure!
6081 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6082 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6083 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6085 Game_time_compression = F1_0;
6087 if ( red_alert_mission() ) {
6088 gameseq_post_event(GS_EVENT_RED_ALERT);
6095 case GS_STATE_DEBRIEF:
6096 game_stop_looped_sounds();
6097 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
6098 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
6103 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6104 multi_df_debrief_init();
6107 case GS_STATE_LOAD_MISSION_MENU:
6108 mission_load_menu_init();
6111 case GS_STATE_SIMULATOR_ROOM:
6115 case GS_STATE_CAMPAIGN_ROOM:
6116 campaign_room_init();
6119 case GS_STATE_RED_ALERT:
6120 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6124 case GS_STATE_CMD_BRIEF: {
6125 int team_num = 0; // team number used as index for which cmd brief to use.
6127 if (old_state == GS_STATE_OPTIONS_MENU) {
6131 main_hall_stop_music();
6132 main_hall_stop_ambient();
6134 if (Game_mode & GM_NORMAL) {
6135 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
6136 // MWA: or from options or hotkey screens
6137 // JH: or if the command brief state already did this
6138 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
6139 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
6140 if ( !game_start_mission() ) // this should put us into a new state on failure!
6145 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
6146 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
6147 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
6149 cmd_brief_init(team_num);
6155 case GS_STATE_SHIP_SELECT:
6159 case GS_STATE_WEAPON_SELECT:
6160 weapon_select_init();
6163 case GS_STATE_TEAM_SELECT:
6167 case GS_STATE_GAME_PAUSED:
6172 case GS_STATE_DEBUG_PAUSED:
6173 // game_stop_time();
6174 // os_set_title("FreeSpace - PAUSED");
6177 case GS_STATE_TRAINING_PAUSED:
6184 case GS_STATE_OPTIONS_MENU:
6186 options_menu_init();
6189 case GS_STATE_GAME_PLAY:
6190 // coming from the gameplay state or the main menu, we might need to load the mission
6191 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
6192 if ( !game_start_mission() ) // this should put us into a new state.
6197 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
6198 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
6199 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
6200 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
6201 (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) ) {
6202 // JAS: Used to do all paging here.
6206 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
6210 main_hall_stop_music();
6211 main_hall_stop_ambient();
6212 event_music_first_pattern(); // start the first pattern
6215 // special code that restores player ship selection and weapons loadout when doing a quick start
6216 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
6217 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
6218 wss_direct_restore_loadout();
6222 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
6223 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
6224 event_music_first_pattern(); // start the first pattern
6227 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
6228 event_music_first_pattern(); // start the first pattern
6230 player_restore_target_and_weapon_link_prefs();
6232 Game_mode |= GM_IN_MISSION;
6235 // required to truely make mouse deltas zeroed in debug mouse code
6236 void mouse_force_pos(int x, int y);
6237 if (!Is_standalone) {
6238 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6244 // only start time if in single player, or coming from multi wait state
6247 (Game_mode & GM_NORMAL) &&
6248 (old_state != GS_STATE_VIEW_CUTSCENES)
6250 (Game_mode & GM_MULTIPLAYER) && (
6251 (old_state == GS_STATE_MULTI_PAUSED) ||
6252 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6258 // when coming from the multi paused state, reset the timestamps
6259 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6260 multi_reset_timestamps();
6263 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6264 // initialize all object update details
6265 multi_oo_gameplay_init();
6268 // under certain circumstances, the server should reset the object update rate limiting stuff
6269 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6270 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6272 // reinitialize the rate limiting system for all clients
6273 multi_oo_rate_init_all();
6276 // multiplayer clients should always re-initialize their control info rate limiting system
6277 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6278 multi_oo_rate_init_all();
6282 if(Game_mode & GM_MULTIPLAYER){
6283 multi_ping_reset_players();
6286 Game_subspace_effect = 0;
6287 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6288 Game_subspace_effect = 1;
6289 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6290 game_start_subspace_ambient_sound();
6294 sound_env_set(&Game_sound_env);
6295 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6297 // clear multiplayer button info i
6298 extern button_info Multi_ship_status_bi;
6299 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6302 case GS_STATE_HUD_CONFIG:
6306 case GS_STATE_MULTI_JOIN_GAME:
6307 multi_join_clear_game_list();
6309 if (old_state != GS_STATE_OPTIONS_MENU) {
6310 multi_join_game_init();
6315 case GS_STATE_MULTI_HOST_SETUP:
6316 // don't reinitialize if we're coming back from the host options screen
6317 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6318 multi_create_game_init();
6323 case GS_STATE_MULTI_CLIENT_SETUP:
6324 if (old_state != GS_STATE_OPTIONS_MENU) {
6325 multi_game_client_setup_init();
6330 case GS_STATE_CONTROL_CONFIG:
6331 control_config_init();
6334 case GS_STATE_TECH_MENU:
6338 case GS_STATE_BARRACKS_MENU:
6339 if(old_state != GS_STATE_VIEW_MEDALS){
6344 case GS_STATE_MISSION_LOG_SCROLLBACK:
6345 hud_scrollback_init();
6348 case GS_STATE_DEATH_DIED:
6349 Player_died_time = timestamp(10);
6351 if(!(Game_mode & GM_MULTIPLAYER)){
6352 player_show_death_message();
6354 Game_mode |= GM_DEAD_DIED;
6357 case GS_STATE_DEATH_BLEW_UP:
6358 if ( !popupdead_is_active() ) {
6359 Player_ai->target_objnum = -1;
6362 // stop any local EMP effect
6365 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6366 Game_mode |= GM_DEAD_BLEW_UP;
6367 Show_viewing_from_self = 0;
6369 // timestamp how long we should wait before displaying the died popup
6370 if ( !popupdead_is_active() ) {
6371 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6375 case GS_STATE_GAMEPLAY_HELP:
6376 gameplay_help_init();
6379 case GS_STATE_CREDITS:
6380 main_hall_stop_music();
6381 main_hall_stop_ambient();
6385 case GS_STATE_VIEW_MEDALS:
6386 medal_main_init(Player);
6389 case GS_STATE_SHOW_GOALS:
6390 mission_show_goals_init();
6393 case GS_STATE_HOTKEY_SCREEN:
6394 mission_hotkey_init();
6397 case GS_STATE_MULTI_MISSION_SYNC:
6398 // if we're coming from the options screen, don't do any
6399 if(old_state == GS_STATE_OPTIONS_MENU){
6403 switch(Multi_sync_mode){
6404 case MULTI_SYNC_PRE_BRIEFING:
6405 // if moving from game forming to the team select state
6408 case MULTI_SYNC_POST_BRIEFING:
6409 // if moving from briefing into the mission itself
6412 // tell everyone that we're now loading data
6413 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6414 send_netplayer_update_packet();
6416 // JAS: Used to do all paging here!!!!
6418 Net_player->state = NETPLAYER_STATE_WAITING;
6419 send_netplayer_update_packet();
6421 Game_time_compression = F1_0;
6423 case MULTI_SYNC_INGAME:
6429 case GS_STATE_VIEW_CUTSCENES:
6430 cutscenes_screen_init();
6433 case GS_STATE_MULTI_STD_WAIT:
6434 multi_standalone_wait_init();
6437 case GS_STATE_STANDALONE_MAIN:
6438 // don't initialize if we're coming from one of these 2 states unless there are no
6439 // players left (reset situation)
6440 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6441 standalone_main_init();
6445 case GS_STATE_MULTI_PAUSED:
6449 case GS_STATE_INGAME_PRE_JOIN:
6450 multi_ingame_select_init();
6453 case GS_STATE_STANDALONE_POSTGAME:
6454 multi_standalone_postgame_init();
6457 case GS_STATE_INITIAL_PLAYER_SELECT:
6458 player_select_init();
6461 case GS_STATE_MULTI_START_GAME:
6462 multi_start_game_init();
6465 case GS_STATE_MULTI_HOST_OPTIONS:
6466 multi_host_options_init();
6469 case GS_STATE_END_OF_CAMPAIGN:
6470 mission_campaign_end_init();
6473 case GS_STATE_LOOP_BRIEF:
6480 // do stuff that may need to be done regardless of state
6481 void game_do_state_common(int state,int no_networking)
6483 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6484 snd_do_frame(); // update sound system
6485 event_music_do_frame(); // music needs to play across many states
6487 multi_log_process();
6489 if (no_networking) {
6493 // maybe do a multiplayer frame based on game mode and state type
6494 if (Game_mode & GM_MULTIPLAYER) {
6496 case GS_STATE_OPTIONS_MENU:
6497 case GS_STATE_GAMEPLAY_HELP:
6498 case GS_STATE_HOTKEY_SCREEN:
6499 case GS_STATE_HUD_CONFIG:
6500 case GS_STATE_CONTROL_CONFIG:
6501 case GS_STATE_MISSION_LOG_SCROLLBACK:
6502 case GS_STATE_SHOW_GOALS:
6503 case GS_STATE_VIEW_CUTSCENES:
6504 case GS_STATE_EVENT_DEBUG:
6505 multi_maybe_do_frame();
6509 game_do_networking();
6513 // Called once a frame.
6514 // You should never try to change the state
6515 // in here... if you think you need to, you probably really
6516 // need to post an event, not change the state.
6517 int Game_do_state_should_skip = 0;
6518 void game_do_state(int state)
6520 // always lets the do_state_common() function determine if the state should be skipped
6521 Game_do_state_should_skip = 0;
6523 // legal to set the should skip state anywhere in this function
6524 game_do_state_common(state); // do stuff that may need to be done regardless of state
6526 if(Game_do_state_should_skip){
6531 case GS_STATE_MAIN_MENU:
6532 game_set_frametime(GS_STATE_MAIN_MENU);
6533 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6536 main_hall_do(flFrametime);
6540 case GS_STATE_OPTIONS_MENU:
6541 game_set_frametime(GS_STATE_OPTIONS_MENU);
6542 options_menu_do_frame(flFrametime);
6545 case GS_STATE_BARRACKS_MENU:
6546 game_set_frametime(GS_STATE_BARRACKS_MENU);
6547 barracks_do_frame(flFrametime);
6550 case GS_STATE_TRAINING_MENU:
6551 game_set_frametime(GS_STATE_TRAINING_MENU);
6552 training_menu_do_frame(flFrametime);
6555 case GS_STATE_TECH_MENU:
6556 game_set_frametime(GS_STATE_TECH_MENU);
6557 techroom_do_frame(flFrametime);
6560 case GS_STATE_GAMEPLAY_HELP:
6561 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6562 gameplay_help_do_frame(flFrametime);
6565 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6569 case GS_STATE_GAME_PAUSED:
6573 case GS_STATE_DEBUG_PAUSED:
6575 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6580 case GS_STATE_TRAINING_PAUSED:
6581 game_training_pause_do();
6584 case GS_STATE_LOAD_MISSION_MENU:
6585 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6586 mission_load_menu_do();
6589 case GS_STATE_BRIEFING:
6590 game_set_frametime(GS_STATE_BRIEFING);
6591 brief_do_frame(flFrametime);
6594 case GS_STATE_DEBRIEF:
6595 game_set_frametime(GS_STATE_DEBRIEF);
6596 debrief_do_frame(flFrametime);
6599 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6600 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6601 multi_df_debrief_do();
6604 case GS_STATE_SHIP_SELECT:
6605 game_set_frametime(GS_STATE_SHIP_SELECT);
6606 ship_select_do(flFrametime);
6609 case GS_STATE_WEAPON_SELECT:
6610 game_set_frametime(GS_STATE_WEAPON_SELECT);
6611 weapon_select_do(flFrametime);
6614 case GS_STATE_MISSION_LOG_SCROLLBACK:
6615 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6616 hud_scrollback_do_frame(flFrametime);
6619 case GS_STATE_HUD_CONFIG:
6620 game_set_frametime(GS_STATE_HUD_CONFIG);
6621 hud_config_do_frame(flFrametime);
6624 case GS_STATE_MULTI_JOIN_GAME:
6625 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6626 multi_join_game_do_frame();
6629 case GS_STATE_MULTI_HOST_SETUP:
6630 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6631 multi_create_game_do();
6634 case GS_STATE_MULTI_CLIENT_SETUP:
6635 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6636 multi_game_client_setup_do_frame();
6639 case GS_STATE_CONTROL_CONFIG:
6640 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6641 control_config_do_frame(flFrametime);
6644 case GS_STATE_DEATH_DIED:
6648 case GS_STATE_DEATH_BLEW_UP:
6652 case GS_STATE_SIMULATOR_ROOM:
6653 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6654 sim_room_do_frame(flFrametime);
6657 case GS_STATE_CAMPAIGN_ROOM:
6658 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6659 campaign_room_do_frame(flFrametime);
6662 case GS_STATE_RED_ALERT:
6663 game_set_frametime(GS_STATE_RED_ALERT);
6664 red_alert_do_frame(flFrametime);
6667 case GS_STATE_CMD_BRIEF:
6668 game_set_frametime(GS_STATE_CMD_BRIEF);
6669 cmd_brief_do_frame(flFrametime);
6672 case GS_STATE_CREDITS:
6673 game_set_frametime(GS_STATE_CREDITS);
6674 credits_do_frame(flFrametime);
6677 case GS_STATE_VIEW_MEDALS:
6678 game_set_frametime(GS_STATE_VIEW_MEDALS);
6682 case GS_STATE_SHOW_GOALS:
6683 game_set_frametime(GS_STATE_SHOW_GOALS);
6684 mission_show_goals_do_frame(flFrametime);
6687 case GS_STATE_HOTKEY_SCREEN:
6688 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6689 mission_hotkey_do_frame(flFrametime);
6692 case GS_STATE_VIEW_CUTSCENES:
6693 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6694 cutscenes_screen_do_frame();
6697 case GS_STATE_MULTI_STD_WAIT:
6698 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6699 multi_standalone_wait_do();
6702 case GS_STATE_STANDALONE_MAIN:
6703 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6704 standalone_main_do();
6707 case GS_STATE_MULTI_PAUSED:
6708 game_set_frametime(GS_STATE_MULTI_PAUSED);
6712 case GS_STATE_TEAM_SELECT:
6713 game_set_frametime(GS_STATE_TEAM_SELECT);
6717 case GS_STATE_INGAME_PRE_JOIN:
6718 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6719 multi_ingame_select_do();
6722 case GS_STATE_EVENT_DEBUG:
6724 game_set_frametime(GS_STATE_EVENT_DEBUG);
6725 game_show_event_debug(flFrametime);
6729 case GS_STATE_STANDALONE_POSTGAME:
6730 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6731 multi_standalone_postgame_do();
6734 case GS_STATE_INITIAL_PLAYER_SELECT:
6735 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6739 case GS_STATE_MULTI_MISSION_SYNC:
6740 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6744 case GS_STATE_MULTI_START_GAME:
6745 game_set_frametime(GS_STATE_MULTI_START_GAME);
6746 multi_start_game_do();
6749 case GS_STATE_MULTI_HOST_OPTIONS:
6750 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6751 multi_host_options_do();
6754 case GS_STATE_END_OF_CAMPAIGN:
6755 mission_campaign_end_do();
6758 case GS_STATE_END_DEMO:
6759 game_set_frametime(GS_STATE_END_DEMO);
6760 end_demo_campaign_do();
6763 case GS_STATE_LOOP_BRIEF:
6764 game_set_frametime(GS_STATE_LOOP_BRIEF);
6768 } // end switch(gs_current_state)
6772 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6773 int game_do_ram_check(int ram_in_bytes)
6775 if ( ram_in_bytes < 30*1024*1024 ) {
6776 int allowed_to_run = 1;
6777 if ( ram_in_bytes < 25*1024*1024 ) {
6782 int Freespace_total_ram_MB;
6783 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6785 if ( allowed_to_run ) {
6787 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);
6792 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6793 if ( msgbox_rval == IDCANCEL ) {
6800 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);
6802 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6813 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6814 // If so, copy it over and remove the update directory.
6815 void game_maybe_update_launcher(char *exe_dir)
6818 char src_filename[MAX_PATH];
6819 char dest_filename[MAX_PATH];
6821 strcpy(src_filename, exe_dir);
6822 strcat(src_filename, NOX("\\update\\freespace.exe"));
6824 strcpy(dest_filename, exe_dir);
6825 strcat(dest_filename, NOX("\\freespace.exe"));
6827 // see if src_filename exists
6829 fp = fopen(src_filename, "rb");
6835 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6837 // copy updated freespace.exe to freespace exe dir
6838 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6839 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 );
6843 // delete the file in the update directory
6844 DeleteFile(src_filename);
6846 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6847 char update_dir[MAX_PATH];
6848 strcpy(update_dir, exe_dir);
6849 strcat(update_dir, NOX("\\update"));
6850 RemoveDirectory(update_dir);
6856 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6860 int sub_total_destroyed = 0;
6864 // get the total for all his children
6865 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6866 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6869 // find the # of faces for this _individual_ object
6870 total = submodel_get_num_polys(model_num, sm);
6871 if(strstr(pm->submodel[sm].name, "-destroyed")){
6872 sub_total_destroyed = total;
6876 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6879 *out_total += total + sub_total;
6880 *out_destroyed_total += sub_total_destroyed;
6883 #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);
6884 void game_spew_pof_info()
6886 char *pof_list[1000];
6889 int idx, model_num, i, j;
6891 int total, root_total, model_total, destroyed_total, counted;
6895 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6897 // spew info on all the pofs
6903 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6908 for(idx=0; idx<num_files; idx++, counted++){
6909 sprintf(str, "%s.pof", pof_list[idx]);
6910 model_num = model_load(str, 0, NULL);
6912 pm = model_get(model_num);
6914 // if we have a real model
6919 // go through and print all raw submodels
6920 cfputs("RAW\n", out);
6923 for (i=0; i<pm->n_models; i++) {
6924 total = submodel_get_num_polys(model_num, i);
6926 model_total += total;
6927 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6930 sprintf(str, "Model total %d\n", model_total);
6933 // now go through and do it by LOD
6934 cfputs("BY LOD\n\n", out);
6935 for(i=0; i<pm->n_detail_levels; i++){
6936 sprintf(str, "LOD %d\n", i);
6940 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6942 destroyed_total = 0;
6943 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6944 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6947 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6950 sprintf(str, "TOTAL: %d\n", total + root_total);
6952 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6954 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6957 cfputs("------------------------------------------------------------------------\n\n", out);
6961 if(counted >= MAX_POLYGON_MODELS - 5){
6974 game_spew_pof_info();
6977 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6982 // Don't let more than one instance of Freespace run.
6983 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6985 SetForegroundWindow(hwnd);
6990 // Find out how much RAM is on this machine
6993 ms.dwLength = sizeof(MEMORYSTATUS);
6994 GlobalMemoryStatus(&ms);
6995 Freespace_total_ram = ms.dwTotalPhys;
6997 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
7001 if ( ms.dwTotalVirtual < 1024 ) {
7002 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
7006 if (!vm_init(24*1024*1024)) {
7007 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 );
7011 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
7013 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);
7021 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
7022 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
7023 seem worth bothering with.
7027 lResult = RegOpenKeyEx(
7028 HKEY_LOCAL_MACHINE, // Where it is
7029 "Software\\Microsoft\\DirectX", // name of key
7030 NULL, // DWORD reserved
7031 KEY_QUERY_VALUE, // Allows all changes
7032 &hKey // Location to store key
7035 if (lResult == ERROR_SUCCESS) {
7037 DWORD dwType, dwLen;
7040 lResult = RegQueryValueEx(
7041 hKey, // Handle to key
7042 "Version", // The values name
7043 NULL, // DWORD reserved
7044 &dwType, // What kind it is
7045 (ubyte *) version, // value to set
7046 &dwLen // How many bytes to set
7049 if (lResult == ERROR_SUCCESS) {
7050 dx_version = atoi(strstr(version, ".") + 1);
7054 DWORD dwType, dwLen;
7057 lResult = RegQueryValueEx(
7058 hKey, // Handle to key
7059 "InstalledVersion", // The values name
7060 NULL, // DWORD reserved
7061 &dwType, // What kind it is
7062 (ubyte *) &val, // value to set
7063 &dwLen // How many bytes to set
7066 if (lResult == ERROR_SUCCESS) {
7074 if (dx_version < 3) {
7075 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
7076 "latest version of DirectX at:\n\n"
7077 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
7079 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
7080 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
7085 //=====================================================
7086 // Make sure we're running in the right directory.
7090 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
7091 char *p = exe_dir + strlen(exe_dir);
7093 // chop off the filename
7094 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
7100 if ( strlen(exe_dir) > 0 ) {
7101 SetCurrentDirectory(exe_dir);
7104 // check for updated freespace.exe
7105 game_maybe_update_launcher(exe_dir);
7113 extern void windebug_memwatch_init();
7114 windebug_memwatch_init();
7118 parse_cmdline(szCmdLine);
7120 #ifdef STANDALONE_ONLY_BUILD
7122 nprintf(("Network", "Standalone running"));
7125 nprintf(("Network", "Standalone running"));
7133 // maybe spew pof stuff
7134 if(Cmdline_spew_pof_info){
7135 game_spew_pof_info();
7140 // non-demo, non-standalone, play the intro movie
7146 // to avoid crashes on debug build
7147 for (i=0; i<5; i++) {
7151 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) ){
7153 #if defined(OEM_BUILD)
7154 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
7156 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
7157 #endif // defined(OEM_BUILD)
7160 for (int i=0; i<5; i++) {
7161 if (plist[i] != NULL) {
7169 if ( !Is_standalone ) {
7171 // release -- movies always play
7174 // 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
7175 movie_play( NOX("intro.mve"), 0 );
7177 // debug version, movie will only play with -showmovies
7178 #elif !defined(NDEBUG)
7180 movie_play( NOX("intro.mve"), 0);
7183 if ( Cmdline_show_movies )
7184 movie_play( NOX("intro.mve"), 0 );
7193 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
7195 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
7199 // only important for non THREADED mode
7202 state = gameseq_process_events();
7203 if ( state == GS_STATE_QUIT_GAME ){
7208 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7210 demo_upsell_show_screens();
7212 #elif defined(OEM_BUILD)
7213 // show upsell screens on exit
7214 oem_upsell_show_screens();
7221 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7227 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7229 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
7231 // Do nothing here - RecordExceptionInfo() has already done
7232 // everything that is needed. Actually this code won't even
7233 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
7234 // the __except clause.
7238 nprintf(("WinMain", "exceptions shall fall through"));
7240 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7246 // launcher the fslauncher program on exit
7247 void game_launch_launcher_on_exit()
7251 PROCESS_INFORMATION pi;
7252 char cmd_line[2048];
7253 char original_path[1024] = "";
7255 memset( &si, 0, sizeof(STARTUPINFO) );
7259 _getcwd(original_path, 1023);
7261 // set up command line
7262 strcpy(cmd_line, original_path);
7263 strcat(cmd_line, "\\");
7264 strcat(cmd_line, LAUNCHER_FNAME);
7265 strcat(cmd_line, " -straight_to_update");
7267 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7268 cmd_line, // pointer to command line string
7269 NULL, // pointer to process security attributes
7270 NULL, // pointer to thread security attributes
7271 FALSE, // handle inheritance flag
7272 CREATE_DEFAULT_ERROR_MODE, // creation flags
7273 NULL, // pointer to new environment block
7274 NULL, // pointer to current directory name
7275 &si, // pointer to STARTUPINFO
7276 &pi // pointer to PROCESS_INFORMATION
7278 // to eliminate build warnings
7288 // This function is called when FreeSpace terminates normally.
7290 void game_shutdown(void)
7296 // don't ever flip a page on the standalone!
7297 if(!(Game_mode & GM_STANDALONE_SERVER)){
7303 // if the player has left the "player select" screen and quit the game without actually choosing
7304 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7305 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7309 // load up common multiplayer icons
7310 multi_unload_common_icons();
7312 shockwave_close(); // release any memory used by shockwave system
7313 fireball_close(); // free fireball system
7314 ship_close(); // free any memory that was allocated for the ships
7315 weapon_close(); // free any memory that was allocated for the weapons
7316 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7317 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7318 bm_unload_all(); // free bitmaps
7319 mission_campaign_close(); // close out the campaign stuff
7320 mission_campaign_shutdown(); // get anything that mission_campaign_close can't do
7321 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7323 #ifdef MULTI_USE_LAG
7327 // the menu close functions will unload the bitmaps if they were displayed during the game
7328 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7331 context_help_close(); // close out help system
7332 training_menu_close();
7333 lcl_close(); // be sure localization is closed out
7336 // free left-over memory from parsed tables
7337 cutscene_tbl_close();
7339 scoring_tbl_close();
7341 extern void joy_close();
7344 audiostream_close();
7346 event_music_close();
7350 // HACKITY HACK HACK
7351 // if this flag is set, we should be firing up the launcher when exiting freespace
7352 extern int Multi_update_fireup_launcher_on_exit;
7353 if(Multi_update_fireup_launcher_on_exit){
7354 game_launch_launcher_on_exit();
7358 // game_stop_looped_sounds()
7360 // This function will call the appropriate stop looped sound functions for those
7361 // modules which use looping sounds. It is not enough just to stop a looping sound
7362 // at the DirectSound level, the game is keeping track of looping sounds, and this
7363 // function is used to inform the game that looping sounds are being halted.
7365 void game_stop_looped_sounds()
7367 hud_stop_looped_locking_sounds();
7368 hud_stop_looped_engine_sounds();
7369 afterburner_stop_sounds();
7370 player_stop_looped_sounds();
7371 obj_snd_stop_all(); // stop all object-linked persistant sounds
7372 game_stop_subspace_ambient_sound();
7373 snd_stop(Radar_static_looping);
7374 Radar_static_looping = -1;
7375 snd_stop(Target_static_looping);
7376 shipfx_stop_engine_wash_sound();
7377 Target_static_looping = -1;
7380 //////////////////////////////////////////////////////////////////////////
7382 // Code for supporting an animating mouse pointer
7385 //////////////////////////////////////////////////////////////////////////
7387 typedef struct animating_obj
7396 static animating_obj Animating_mouse;
7398 // ----------------------------------------------------------------------------
7399 // init_animating_pointer()
7401 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7402 // gets properly initialized
7404 void init_animating_pointer()
7406 Animating_mouse.first_frame = -1;
7407 Animating_mouse.num_frames = 0;
7408 Animating_mouse.current_frame = -1;
7409 Animating_mouse.time = 0.0f;
7410 Animating_mouse.elapsed_time = 0.0f;
7413 // ----------------------------------------------------------------------------
7414 // load_animating_pointer()
7416 // Called at game init to load in the frames for the animating mouse pointer
7418 // input: filename => filename of animation file that holds the animation
7420 void load_animating_pointer(char *filename, int dx, int dy)
7425 init_animating_pointer();
7427 am = &Animating_mouse;
7428 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7429 if ( am->first_frame == -1 )
7430 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7431 am->current_frame = 0;
7432 am->time = am->num_frames / i2fl(fps);
7435 // ----------------------------------------------------------------------------
7436 // unload_animating_pointer()
7438 // Called at game shutdown to free the memory used to store the animation frames
7440 void unload_animating_pointer()
7445 am = &Animating_mouse;
7446 for ( i = 0; i < am->num_frames; i++ ) {
7447 Assert( (am->first_frame+i) >= 0 );
7448 bm_release(am->first_frame + i);
7451 am->first_frame = -1;
7453 am->current_frame = -1;
7456 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7457 void game_render_mouse(float frametime)
7462 // if animating cursor exists, play the next frame
7463 am = &Animating_mouse;
7464 if ( am->first_frame != -1 ) {
7465 mouse_get_pos(&mx, &my);
7466 am->elapsed_time += frametime;
7467 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7468 if ( am->current_frame >= am->num_frames ) {
7469 am->current_frame = 0;
7470 am->elapsed_time = 0.0f;
7472 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7476 // ----------------------------------------------------------------------------
7477 // game_maybe_draw_mouse()
7479 // determines whether to draw the mouse pointer at all, and what frame of
7480 // animation to use if the mouse is animating
7482 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7484 // input: frametime => elapsed frame time in seconds since last call
7486 void game_maybe_draw_mouse(float frametime)
7490 game_state = gameseq_get_state();
7492 switch ( game_state ) {
7493 case GS_STATE_GAME_PAUSED:
7494 // case GS_STATE_MULTI_PAUSED:
7495 case GS_STATE_GAME_PLAY:
7496 case GS_STATE_DEATH_DIED:
7497 case GS_STATE_DEATH_BLEW_UP:
7498 if ( popup_active() || popupdead_is_active() ) {
7510 if ( !Mouse_hidden )
7511 game_render_mouse(frametime);
7515 void game_do_training_checks()
7519 waypoint_list *wplp;
7521 if (Training_context & TRAINING_CONTEXT_SPEED) {
7522 s = (int) Player_obj->phys_info.fspeed;
7523 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7524 if (!Training_context_speed_set) {
7525 Training_context_speed_set = 1;
7526 Training_context_speed_timestamp = timestamp();
7530 Training_context_speed_set = 0;
7533 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7534 wplp = &Waypoint_lists[Training_context_path];
7535 if (wplp->count > Training_context_goal_waypoint) {
7536 i = Training_context_goal_waypoint;
7538 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7539 if (d <= Training_context_distance) {
7540 Training_context_at_waypoint = i;
7541 if (Training_context_goal_waypoint == i) {
7542 Training_context_goal_waypoint++;
7543 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7550 if (i == wplp->count)
7553 } while (i != Training_context_goal_waypoint);
7557 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7558 Players_target = Player_ai->target_objnum;
7559 Players_targeted_subsys = Player_ai->targeted_subsys;
7560 Players_target_timestamp = timestamp();
7564 /////////// Following is for event debug view screen
7568 #define EVENT_DEBUG_MAX 5000
7569 #define EVENT_DEBUG_EVENT 0x8000
7571 int Event_debug_index[EVENT_DEBUG_MAX];
7574 void game_add_event_debug_index(int n, int indent)
7576 if (ED_count < EVENT_DEBUG_MAX)
7577 Event_debug_index[ED_count++] = n | (indent << 16);
7580 void game_add_event_debug_sexp(int n, int indent)
7585 if (Sexp_nodes[n].first >= 0) {
7586 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7587 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7591 game_add_event_debug_index(n, indent);
7592 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7593 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7595 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7598 void game_event_debug_init()
7603 for (e=0; e<Num_mission_events; e++) {
7604 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7605 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7609 void game_show_event_debug(float frametime)
7613 int font_height, font_width;
7615 static int scroll_offset = 0;
7617 k = game_check_key();
7623 if (scroll_offset < 0)
7633 scroll_offset -= 20;
7634 if (scroll_offset < 0)
7639 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7643 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7649 gr_set_color_fast(&Color_bright);
7651 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7653 gr_set_color_fast(&Color_normal);
7655 gr_get_string_size(&font_width, &font_height, NOX("test"));
7656 y_max = gr_screen.max_h - font_height - 5;
7660 while (k < ED_count) {
7661 if (y_index > y_max)
7664 z = Event_debug_index[k];
7665 if (z & EVENT_DEBUG_EVENT) {
7667 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7668 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7669 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7670 Mission_events[z].repeat_count, Mission_events[z].interval);
7678 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7679 switch (Sexp_nodes[z & 0x7fff].value) {
7681 strcat(buf, NOX(" (True)"));
7685 strcat(buf, NOX(" (False)"));
7688 case SEXP_KNOWN_TRUE:
7689 strcat(buf, NOX(" (Always true)"));
7692 case SEXP_KNOWN_FALSE:
7693 strcat(buf, NOX(" (Always false)"));
7696 case SEXP_CANT_EVAL:
7697 strcat(buf, NOX(" (Can't eval)"));
7701 case SEXP_NAN_FOREVER:
7702 strcat(buf, NOX(" (Not a number)"));
7707 gr_printf(10, y_index, buf);
7708 y_index += font_height;
7721 extern int Tmap_npixels;
7723 int Tmap_num_too_big = 0;
7724 int Num_models_needing_splitting = 0;
7726 void Time_model( int modelnum )
7728 // mprintf(( "Timing ship '%s'\n", si->name ));
7730 vector eye_pos, model_pos;
7731 matrix eye_orient, model_orient;
7733 polymodel *pm = model_get( modelnum );
7735 int l = strlen(pm->filename);
7737 if ( (l == '/') || (l=='\\') || (l==':')) {
7743 char *pof_file = &pm->filename[l];
7745 int model_needs_splitting = 0;
7747 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7749 for (i=0; i<pm->n_textures; i++ ) {
7750 char filename[1024];
7753 int bmp_num = pm->original_textures[i];
7754 if ( bmp_num > -1 ) {
7755 bm_get_palette(pm->original_textures[i], pal, filename );
7757 bm_get_info( pm->original_textures[i],&w, &h );
7760 if ( (w > 512) || (h > 512) ) {
7761 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7763 model_needs_splitting++;
7766 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7770 if ( model_needs_splitting ) {
7771 Num_models_needing_splitting++;
7773 eye_orient = model_orient = vmd_identity_matrix;
7774 eye_pos = model_pos = vmd_zero_vector;
7776 eye_pos.xyz.z = -pm->rad*2.0f;
7778 vector eye_to_model;
7780 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7781 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7783 fix t1 = timer_get_fixed_seconds();
7786 ta.p = ta.b = ta.h = 0.0f;
7791 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7793 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7795 modelstats_num_polys = modelstats_num_verts = 0;
7797 while( ta.h < PI2 ) {
7800 vm_angles_2_matrix(&m1, &ta );
7801 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7808 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7810 model_clear_instance( modelnum );
7811 model_set_detail_level(0); // use highest detail level
7812 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7820 int k = key_inkey();
7821 if ( k == KEY_ESC ) {
7826 fix t2 = timer_get_fixed_seconds();
7828 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7829 //bitmaps_used_this_frame /= framecount;
7831 modelstats_num_polys /= framecount;
7832 modelstats_num_verts /= framecount;
7834 Tmap_npixels /=framecount;
7837 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7838 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 );
7839 // 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 );
7845 int Time_models = 0;
7846 DCF_BOOL( time_models, Time_models );
7848 void Do_model_timings_test()
7852 if ( !Time_models ) return;
7854 mprintf(( "Timing models!\n" ));
7858 ubyte model_used[MAX_POLYGON_MODELS];
7859 int model_id[MAX_POLYGON_MODELS];
7860 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7865 for (i=0; i<Num_ship_types; i++ ) {
7866 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7868 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7869 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7872 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7873 if ( !Texture_fp ) return;
7875 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7876 if ( !Time_fp ) return;
7878 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7879 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7881 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7882 if ( model_used[i] ) {
7883 Time_model( model_id[i] );
7887 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7888 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7897 // Call this function when you want to inform the player that a feature is not
7898 // enabled in the DEMO version of FreSpace
7899 void game_feature_not_in_demo_popup()
7901 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7904 // format the specified time (fixed point) into a nice string
7905 void game_format_time(fix m_time,char *time_str)
7908 int hours,minutes,seconds;
7911 mtime = f2fl(m_time);
7913 // get the hours, minutes and seconds
7914 hours = (int)(mtime / 3600.0f);
7916 mtime -= (3600.0f * (float)hours);
7918 seconds = (int)mtime%60;
7919 minutes = (int)mtime/60;
7921 // print the hour if necessary
7923 sprintf(time_str,XSTR( "%d:", 201),hours);
7924 // if there are less than 10 minutes, print a leading 0
7926 strcpy(tmp,NOX("0"));
7927 strcat(time_str,tmp);
7931 // print the minutes
7933 sprintf(tmp,XSTR( "%d:", 201),minutes);
7934 strcat(time_str,tmp);
7936 sprintf(time_str,XSTR( "%d:", 201),minutes);
7939 // print the seconds
7941 strcpy(tmp,NOX("0"));
7942 strcat(time_str,tmp);
7944 sprintf(tmp,"%d",seconds);
7945 strcat(time_str,tmp);
7948 // Stuff version string in *str.
7949 void get_version_string(char *str)
7952 if ( FS_VERSION_BUILD == 0 ) {
7953 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7955 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7958 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7960 #elif defined (OEM_BUILD)
7961 strcat(str, " (OEM)");
7967 char myname[_MAX_PATH];
7968 int namelen, major, minor, build, waste;
7969 unsigned int buf_size;
7975 // Find my EXE file name
7976 hMod = GetModuleHandle(NULL);
7977 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7979 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7980 infop = (char *)malloc(version_size);
7981 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7983 // get the product version
7984 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7985 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7987 sprintf(str,"Dv%d.%02d",major, minor);
7989 sprintf(str,"v%d.%02d",major, minor);
7994 void get_version_string_short(char *str)
7996 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7999 // ----------------------------------------------------------------
8001 // OEM UPSELL SCREENS BEGIN
8003 // ----------------------------------------------------------------
8004 #if defined(OEM_BUILD)
8006 #define NUM_OEM_UPSELL_SCREENS 3
8007 #define OEM_UPSELL_SCREEN_DELAY 10000
8009 static int Oem_upsell_bitmaps_loaded = 0;
8010 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
8011 static int Oem_upsell_screen_number = 0;
8012 static int Oem_upsell_show_next_bitmap_time;
8015 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
8028 static int Oem_normal_cursor = -1;
8029 static int Oem_web_cursor = -1;
8030 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
8031 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
8033 void oem_upsell_next_screen()
8035 Oem_upsell_screen_number++;
8036 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
8037 // extra long delay, mouse shown on last upsell
8038 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
8042 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8046 void oem_upsell_load_bitmaps()
8050 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8051 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
8055 void oem_upsell_unload_bitmaps()
8059 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8060 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
8061 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
8066 Oem_upsell_bitmaps_loaded = 0;
8069 // clickable hotspot on 3rd OEM upsell screen
8070 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
8072 28, 350, 287, 96 // x, y, w, h
8075 45, 561, 460, 152 // x, y, w, h
8079 void oem_upsell_show_screens()
8081 int current_time, k;
8084 if ( !Oem_upsell_bitmaps_loaded ) {
8085 oem_upsell_load_bitmaps();
8086 Oem_upsell_bitmaps_loaded = 1;
8089 // may use upsell screens more than once
8090 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8091 Oem_upsell_screen_number = 0;
8097 int nframes; // used to pass, not really needed (should be 1)
8098 Oem_normal_cursor = gr_get_cursor_bitmap();
8099 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
8100 Assert(Oem_web_cursor >= 0);
8101 if (Oem_web_cursor < 0) {
8102 Oem_web_cursor = Oem_normal_cursor;
8107 //oem_reset_trailer_timer();
8109 current_time = timer_get_milliseconds();
8114 // advance screen on keypress or timeout
8115 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
8116 oem_upsell_next_screen();
8119 // check if we are done
8120 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
8121 Oem_upsell_screen_number--;
8124 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
8129 // show me the upsell
8130 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
8131 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
8135 // if this is the 3rd upsell, make it clickable, d00d
8136 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
8138 int button_state = mouse_get_pos(&mx, &my);
8139 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])
8140 && (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]) )
8143 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
8146 if (button_state & MOUSE_LEFT_BUTTON) {
8148 multi_pxo_url(OEM_UPSELL_URL);
8152 // switch cursor back to normal one
8153 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8158 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8168 oem_upsell_unload_bitmaps();
8170 // switch cursor back to normal one
8171 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8175 #endif // defined(OEM_BUILD)
8176 // ----------------------------------------------------------------
8178 // OEM UPSELL SCREENS END
8180 // ----------------------------------------------------------------
8184 // ----------------------------------------------------------------
8186 // DEMO UPSELL SCREENS BEGIN
8188 // ----------------------------------------------------------------
8190 #if defined(FS2_DEMO) || defined(FS1_DEMO)
8193 #define NUM_DEMO_UPSELL_SCREENS 2
8195 #define NUM_DEMO_UPSELL_SCREENS 4
8197 #define DEMO_UPSELL_SCREEN_DELAY 3000
8199 static int Demo_upsell_bitmaps_loaded = 0;
8200 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
8201 static int Demo_upsell_screen_number = 0;
8202 static int Demo_upsell_show_next_bitmap_time;
8205 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
8231 void demo_upsell_next_screen()
8233 Demo_upsell_screen_number++;
8234 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
8235 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
8237 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8241 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
8242 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8243 #ifndef HARDWARE_ONLY
8244 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8251 void demo_upsell_load_bitmaps()
8255 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8256 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
8260 void demo_upsell_unload_bitmaps()
8264 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8265 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8266 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8271 Demo_upsell_bitmaps_loaded = 0;
8274 void demo_upsell_show_screens()
8276 int current_time, k;
8279 if ( !Demo_upsell_bitmaps_loaded ) {
8280 demo_upsell_load_bitmaps();
8281 Demo_upsell_bitmaps_loaded = 1;
8284 // may use upsell screens more than once
8285 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8286 Demo_upsell_screen_number = 0;
8293 demo_reset_trailer_timer();
8295 current_time = timer_get_milliseconds();
8302 // don't time out, wait for keypress
8304 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8305 demo_upsell_next_screen();
8310 demo_upsell_next_screen();
8313 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8314 Demo_upsell_screen_number--;
8317 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8322 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8323 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8328 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8338 demo_upsell_unload_bitmaps();
8343 // ----------------------------------------------------------------
8345 // DEMO UPSELL SCREENS END
8347 // ----------------------------------------------------------------
8350 // ----------------------------------------------------------------
8352 // Subspace Ambient Sound START
8354 // ----------------------------------------------------------------
8356 static int Subspace_ambient_left_channel = -1;
8357 static int Subspace_ambient_right_channel = -1;
8360 void game_start_subspace_ambient_sound()
8362 if ( Subspace_ambient_left_channel < 0 ) {
8363 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8366 if ( Subspace_ambient_right_channel < 0 ) {
8367 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8371 void game_stop_subspace_ambient_sound()
8373 if ( Subspace_ambient_left_channel >= 0 ) {
8374 snd_stop(Subspace_ambient_left_channel);
8375 Subspace_ambient_left_channel = -1;
8378 if ( Subspace_ambient_right_channel >= 0 ) {
8379 snd_stop(Subspace_ambient_right_channel);
8380 Subspace_ambient_right_channel = -1;
8384 // ----------------------------------------------------------------
8386 // Subspace Ambient Sound END
8388 // ----------------------------------------------------------------
8390 // ----------------------------------------------------------------
8392 // CDROM detection code START
8394 // ----------------------------------------------------------------
8396 #define CD_SIZE_72_MINUTE_MAX (697000000)
8398 uint game_get_cd_used_space(char *path)
8402 char use_path[512] = "";
8403 char sub_path[512] = "";
8404 WIN32_FIND_DATA find;
8407 // recurse through all files and directories
8408 strcpy(use_path, path);
8409 strcat(use_path, "*.*");
8410 find_handle = FindFirstFile(use_path, &find);
8413 if(find_handle == INVALID_HANDLE_VALUE){
8419 // subdirectory. make sure to ignore . and ..
8420 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8422 strcpy(sub_path, path);
8423 strcat(sub_path, find.cFileName);
8424 strcat(sub_path, "\\");
8425 total += game_get_cd_used_space(sub_path);
8427 total += (uint)find.nFileSizeLow;
8429 } while(FindNextFile(find_handle, &find));
8432 FindClose(find_handle);
8444 // if volume_name is non-null, the CD name must match that
8445 int find_freespace_cd(char *volume_name)
8448 char oldpath[MAX_PATH];
8452 int volume_match = 0;
8456 GetCurrentDirectory(MAX_PATH, oldpath);
8458 for (i = 0; i < 26; i++)
8464 path[0] = (char)('A'+i);
8465 if (GetDriveType(path) == DRIVE_CDROM) {
8467 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8468 nprintf(("CD", "CD volume: %s\n", volume));
8470 // check for any CD volume
8471 int volume1_present = 0;
8472 int volume2_present = 0;
8473 int volume3_present = 0;
8475 char full_check[512] = "";
8477 // look for setup.exe
8478 strcpy(full_check, path);
8479 strcat(full_check, "setup.exe");
8480 find_handle = _findfirst(full_check, &find);
8481 if(find_handle != -1){
8482 volume1_present = 1;
8483 _findclose(find_handle);
8486 // look for intro.mve
8487 strcpy(full_check, path);
8488 strcat(full_check, "intro.mve");
8489 find_handle = _findfirst(full_check, &find);
8490 if(find_handle != -1){
8491 volume2_present = 1;
8492 _findclose(find_handle);
8495 // look for endpart1.mve
8496 strcpy(full_check, path);
8497 strcat(full_check, "endpart1.mve");
8498 find_handle = _findfirst(full_check, &find);
8499 if(find_handle != -1){
8500 volume3_present = 1;
8501 _findclose(find_handle);
8504 // see if we have the specific CD we're looking for
8505 if ( volume_name ) {
8507 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8511 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8515 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8519 if ( volume1_present || volume2_present || volume3_present ) {
8524 // 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
8525 if ( volume_match ){
8527 // 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
8528 if(volume2_present || volume3_present) {
8529 // first step - check to make sure its a cdrom
8530 if(GetDriveType(path) != DRIVE_CDROM){
8534 #if !defined(OEM_BUILD)
8535 // oem not on 80 min cds, so dont check tha size
8537 uint used_space = game_get_cd_used_space(path);
8538 if(used_space < CD_SIZE_72_MINUTE_MAX){
8541 #endif // !defined(OEM_BUILD)
8549 #endif // RELEASE_REAL
8555 SetCurrentDirectory(oldpath);
8564 int set_cdrom_path(int drive_num)
8568 if (drive_num < 0) { //no CD
8570 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8573 strcpy(Game_CDROM_dir,""); //set directory
8577 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8593 i = find_freespace_cd();
8595 rval = set_cdrom_path(i);
8599 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8601 nprintf(("CD", "FreeSpace CD not found\n"));
8609 int Last_cd_label_found = 0;
8610 char Last_cd_label[256];
8612 int game_cd_changed()
8619 if ( strlen(Game_CDROM_dir) == 0 ) {
8623 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8625 if ( found != Last_cd_label_found ) {
8626 Last_cd_label_found = found;
8628 mprintf(( "CD '%s' was inserted\n", label ));
8631 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8635 if ( Last_cd_label_found ) {
8636 if ( !stricmp( Last_cd_label, label )) {
8637 //mprintf(( "CD didn't change\n" ));
8639 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8643 // none found before, none found now.
8644 //mprintf(( "still no CD...\n" ));
8648 Last_cd_label_found = found;
8650 strcpy( Last_cd_label, label );
8652 strcpy( Last_cd_label, "" );
8663 // check if _any_ FreeSpace2 CDs are in the drive
8664 // return: 1 => CD now in drive
8665 // 0 => Could not find CD, they refuse to put it in the drive
8666 int game_do_cd_check(char *volume_name)
8668 #if !defined(GAME_CD_CHECK)
8674 int num_attempts = 0;
8675 int refresh_files = 0;
8677 int path_set_ok, popup_rval;
8679 cd_drive_num = find_freespace_cd(volume_name);
8680 path_set_ok = set_cdrom_path(cd_drive_num);
8681 if ( path_set_ok ) {
8683 if ( refresh_files ) {
8695 // no CD found, so prompt user
8696 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8698 if ( popup_rval != 1 ) {
8703 if ( num_attempts++ > 5 ) {
8714 // check if _any_ FreeSpace2 CDs are in the drive
8715 // return: 1 => CD now in drive
8716 // 0 => Could not find CD, they refuse to put it in the drive
8717 int game_do_cd_check_specific(char *volume_name, int cdnum)
8722 int num_attempts = 0;
8723 int refresh_files = 0;
8725 int path_set_ok, popup_rval;
8727 cd_drive_num = find_freespace_cd(volume_name);
8728 path_set_ok = set_cdrom_path(cd_drive_num);
8729 if ( path_set_ok ) {
8731 if ( refresh_files ) {
8742 // no CD found, so prompt user
8743 #if defined(DVD_MESSAGE_HACK)
8744 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8746 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8749 if ( popup_rval != 1 ) {
8754 if ( num_attempts++ > 5 ) {
8764 // only need to do this in RELEASE_REAL
8765 int game_do_cd_mission_check(char *filename)
8771 fs_builtin_mission *m = game_find_builtin_mission(filename);
8773 // check for changed CD
8774 if(game_cd_changed()){
8779 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8783 // not builtin, so do a general check (any FS2 CD will do)
8785 return game_do_cd_check();
8788 // does not have any CD requirement, do a general check
8789 if(strlen(m->cd_volume) <= 0){
8790 return game_do_cd_check();
8794 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8796 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8799 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8803 return game_do_cd_check();
8806 // did we find the cd?
8807 if(find_freespace_cd(m->cd_volume) >= 0){
8811 // make sure the volume exists
8812 int num_attempts = 0;
8813 int refresh_files = 0;
8815 int path_set_ok, popup_rval;
8817 cd_drive_num = find_freespace_cd(m->cd_volume);
8818 path_set_ok = set_cdrom_path(cd_drive_num);
8819 if ( path_set_ok ) {
8821 if ( refresh_files ) {
8828 // no CD found, so prompt user
8829 #if defined(DVD_MESSAGE_HACK)
8830 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8832 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8836 if ( popup_rval != 1 ) {
8841 if ( num_attempts++ > 5 ) {
8853 // ----------------------------------------------------------------
8855 // CDROM detection code END
8857 // ----------------------------------------------------------------
8859 // ----------------------------------------------------------------
8861 // Language Autodetection stuff
8864 // this layout order must match Lcl_languages in localize.cpp in order for the
8865 // correct language to be detected
8866 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
8868 1366105450, // English
8870 589986744, // English
8872 -1132430286, // German
8874 -1131728960, // Polish
8877 // default setting is "-1" to use config file with English as fall back
8878 // DO NOT change the default setting here or something uncouth might happen
8879 // in the localization code
8885 // try and open the file to verify
8886 CFILE *detect = cfopen("font01.vf", "rb");
8888 // will use default setting if something went wrong
8893 // get the long checksum of the file
8895 cfseek(detect, 0, SEEK_SET);
8896 cf_chksum_long(detect, &file_checksum);
8900 // now compare the checksum/filesize against known #'s
8901 for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8902 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8907 // notify if a match was not found, include detected checksum
8908 printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8909 printf("Using default language...\n\n");
8915 // End Auto Lang stuff
8917 // ----------------------------------------------------------------
8919 // ----------------------------------------------------------------
8920 // SHIPS TBL VERIFICATION STUFF
8923 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8924 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8925 #define NUM_SHIPS_TBL_CHECKSUMS 3
8927 #define NUM_SHIPS_TBL_CHECKSUMS 1
8931 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8932 1696074201, // FS2 demo
8935 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8936 1603375034, // FS1 DEMO
8939 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8940 -129679197, // FS1 Full 1.06 (US)
8941 7762567, // FS1 SilentThreat
8942 1555372475 // FS1 Full 1.06 (German)
8946 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8947 -463907578, // US - beta 1
8948 1696074201, // FS2 demo
8951 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8952 // -1022810006, // 1.0 FULL
8953 -1254285366 // 1.2 FULL (German)
8957 void verify_ships_tbl()
8961 Game_ships_tbl_valid = 1;
8967 // detect if the packfile exists
8968 CFILE *detect = cfopen("ships.tbl", "rb");
8969 Game_ships_tbl_valid = 0;
8973 Game_ships_tbl_valid = 0;
8977 // get the long checksum of the file
8979 cfseek(detect, 0, SEEK_SET);
8980 cf_chksum_long(detect, &file_checksum);
8984 // now compare the checksum/filesize against known #'s
8985 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8986 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8987 Game_ships_tbl_valid = 1;
8994 DCF(shipspew, "display the checksum for the current ships.tbl")
8997 CFILE *detect = cfopen("ships.tbl", "rb");
8998 // get the long checksum of the file
9000 cfseek(detect, 0, SEEK_SET);
9001 cf_chksum_long(detect, &file_checksum);
9004 dc_printf("%d", file_checksum);
9007 // ----------------------------------------------------------------
9008 // WEAPONS TBL VERIFICATION STUFF
9011 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
9012 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
9013 #define NUM_WEAPONS_TBL_CHECKSUMS 3
9015 #define NUM_WEAPONS_TBL_CHECKSUMS 1
9019 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9020 -266420030, // demo 1
9023 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9024 -1246928725, // FS1 DEMO
9027 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9028 -834598107, // FS1 1.06 Full (US)
9029 -1652231417, // FS1 SilentThreat
9030 720209793 // FS1 1.06 Full (German)
9034 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9035 141718090, // US - beta 1
9036 -266420030, // demo 1
9039 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9040 // 399297860, // 1.0 FULL
9041 -553984927 // 1.2 FULL (german)
9045 void verify_weapons_tbl()
9049 Game_weapons_tbl_valid = 1;
9055 // detect if the packfile exists
9056 CFILE *detect = cfopen("weapons.tbl", "rb");
9057 Game_weapons_tbl_valid = 0;
9061 Game_weapons_tbl_valid = 0;
9065 // get the long checksum of the file
9067 cfseek(detect, 0, SEEK_SET);
9068 cf_chksum_long(detect, &file_checksum);
9072 // now compare the checksum/filesize against known #'s
9073 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
9074 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
9075 Game_weapons_tbl_valid = 1;
9082 DCF(wepspew, "display the checksum for the current weapons.tbl")
9085 CFILE *detect = cfopen("weapons.tbl", "rb");
9086 // get the long checksum of the file
9088 cfseek(detect, 0, SEEK_SET);
9089 cf_chksum_long(detect, &file_checksum);
9092 dc_printf("%d", file_checksum);
9095 // if the game is running using hacked data
9096 int game_hacked_data()
9099 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
9107 void display_title_screen()
9109 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
9110 ///int title_bitmap;
9113 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
9114 if (title_bitmap == -1) {
9120 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9121 extern void d3d_start_frame();
9127 gr_set_bitmap(title_bitmap);
9134 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9135 extern void d3d_stop_frame();
9143 bm_unload(title_bitmap);
9144 #endif // FS2_DEMO || OEM_BUILD || FS1_DEMO
9147 // return true if the game is running with "low memory", which is less than 48MB
9148 bool game_using_low_mem()
9150 if (Use_low_mem == 0) {