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.26 2003/02/20 17:41:07 theoddone33
19 * Userdir patch from Taylor Richards
21 * Revision 1.25 2003/01/30 19:54:10 relnev
22 * ini config option for the frames per second counter (Taylor Richards)
24 * Revision 1.24 2002/08/31 01:39:13 theoddone33
25 * Speed up the renderer a tad
27 * Revision 1.23 2002/08/04 02:31:00 relnev
28 * make numlock not overlap with pause
30 * Revision 1.22 2002/08/02 23:07:03 relnev
31 * don't access the mouse in standalone mode
33 * Revision 1.21 2002/07/28 05:05:08 relnev
34 * removed some old stuff
36 * Revision 1.20 2002/07/24 00:20:41 relnev
39 * Revision 1.19 2002/06/17 06:33:08 relnev
40 * ryan's struct patch for gcc 2.95
42 * Revision 1.18 2002/06/16 04:46:33 relnev
43 * set up correct checksums for demo
45 * Revision 1.17 2002/06/09 04:41:17 relnev
46 * added copyright header
48 * Revision 1.16 2002/06/09 03:16:04 relnev
51 * removed unneeded asm, old sdl 2d setup.
53 * fixed crash caused by opengl_get_region.
55 * Revision 1.15 2002/06/05 08:05:28 relnev
56 * stub/warning removal.
58 * reworked the sound code.
60 * Revision 1.14 2002/06/05 04:03:32 relnev
61 * finished cfilesystem.
63 * removed some old code.
65 * fixed mouse save off-by-one.
69 * Revision 1.13 2002/06/02 04:26:34 relnev
72 * Revision 1.12 2002/06/02 00:31:35 relnev
73 * implemented osregistry
75 * Revision 1.11 2002/06/01 09:00:34 relnev
76 * silly debug memmanager
78 * Revision 1.10 2002/06/01 07:12:32 relnev
79 * a few NDEBUG updates.
81 * removed a few warnings.
83 * Revision 1.9 2002/05/31 03:05:59 relnev
86 * Revision 1.8 2002/05/29 02:52:32 theoddone33
87 * Enable OpenGL renderer
89 * Revision 1.7 2002/05/28 08:52:03 relnev
90 * implemented two assembly stubs.
92 * cleaned up a few warnings.
94 * added a little demo hackery to make it progress a little farther.
96 * Revision 1.6 2002/05/28 06:28:20 theoddone33
97 * Filesystem mods, actually reads some data files now
99 * Revision 1.5 2002/05/28 04:07:28 theoddone33
100 * New graphics stubbing arrangement
102 * Revision 1.4 2002/05/27 22:46:52 theoddone33
103 * Remove more undefined symbols
105 * Revision 1.3 2002/05/26 23:31:18 relnev
106 * added a few files that needed to be compiled
108 * freespace.cpp: now compiles
110 * Revision 1.2 2002/05/07 03:16:44 theoddone33
111 * The Great Newline Fix
113 * Revision 1.1.1.1 2002/05/03 03:28:09 root
117 * 201 6/16/00 3:15p Jefff
118 * sim of the year dvd version changes, a few german soty localization
121 * 200 11/03/99 11:06a Jefff
124 * 199 10/26/99 5:07p Jamest
125 * fixed jeffs dumb debug code
127 * 198 10/25/99 5:53p Jefff
128 * call control_config_common_init() on startup
130 * 197 10/14/99 10:18a Daveb
131 * Fixed incorrect CD checking problem on standalone server.
133 * 196 10/13/99 9:22a Daveb
134 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
135 * related to movies. Fixed launcher spawning from PXO screen.
137 * 195 10/06/99 11:05a Jefff
138 * new oem upsell 3 hotspot coords
140 * 194 10/06/99 10:31a Jefff
143 * 193 10/01/99 9:10a Daveb
146 * 192 9/15/99 4:57a Dave
147 * Updated ships.tbl checksum
149 * 191 9/15/99 3:58a Dave
150 * Removed framerate warning at all times.
152 * 190 9/15/99 3:16a Dave
153 * Remove mt-011.fs2 from the builtin mission list.
155 * 189 9/15/99 1:45a Dave
156 * Don't init joystick on standalone. Fixed campaign mode on standalone.
157 * Fixed no-score-report problem in TvT
159 * 188 9/14/99 6:08a Dave
160 * Updated (final) single, multi, and campaign list.
162 * 187 9/14/99 3:26a Dave
163 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
164 * respawn-too-early problem. Made a few crash points safe.
166 * 186 9/13/99 4:52p Dave
169 * 185 9/12/99 8:09p Dave
170 * Fixed problem where skip-training button would cause mission messages
171 * not to get paged out for the current mission.
173 * 184 9/10/99 11:53a Dave
174 * Shutdown graphics before sound to eliminate apparent lockups when
175 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
177 * 183 9/09/99 11:40p Dave
178 * Handle an Assert() in beam code. Added supernova sounds. Play the right
179 * 2 end movies properly, based upon what the player did in the mission.
181 * 182 9/08/99 10:29p Dave
182 * Make beam sound pausing and unpausing much safer.
184 * 181 9/08/99 10:01p Dave
185 * Make sure game won't run in a drive's root directory. Make sure
186 * standalone routes suqad war messages properly to the host.
188 * 180 9/08/99 3:22p Dave
189 * Updated builtin mission list.
191 * 179 9/08/99 12:01p Jefff
192 * fixed Game_builtin_mission_list typo on Training-2.fs2
194 * 178 9/08/99 9:48a Andsager
195 * Add force feedback for engine wash.
197 * 177 9/07/99 4:01p Dave
198 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
199 * does everything properly (setting up address when binding). Remove
200 * black rectangle background from UI_INPUTBOX.
202 * 176 9/13/99 2:40a Dave
203 * Comment in full 80 minute CD check for RELEASE_REAL builds.
205 * 175 9/06/99 6:38p Dave
206 * Improved CD detection code.
208 * 174 9/06/99 1:30a Dave
209 * Intermediate checkin. Started on enforcing CD-in-drive to play the
212 * 173 9/06/99 1:16a Dave
213 * Make sure the user sees the intro movie.
215 * 172 9/04/99 8:00p Dave
216 * Fixed up 1024 and 32 bit movie support.
218 * 171 9/03/99 1:32a Dave
219 * CD checking by act. Added support to play 2 cutscenes in a row
220 * seamlessly. Fixed super low level cfile bug related to files in the
221 * root directory of a CD. Added cheat code to set campaign mission # in
224 * 170 9/01/99 10:49p Dave
225 * Added nice SquadWar checkbox to the client join wait screen.
227 * 169 9/01/99 10:14a Dave
230 * 168 8/29/99 4:51p Dave
231 * Fixed damaged checkin.
233 * 167 8/29/99 4:18p Andsager
234 * New "burst" limit for friendly damage. Also credit more damage done
235 * against large friendly ships.
237 * 166 8/27/99 6:38p Alanl
238 * crush the blasted repeating messages bug
240 * 164 8/26/99 9:09p Dave
241 * Force framerate check in everything but a RELEASE_REAL build.
243 * 163 8/26/99 9:45a Dave
244 * First pass at easter eggs and cheats.
246 * 162 8/24/99 8:55p Dave
247 * Make sure nondimming pixels work properly in tech menu.
249 * 161 8/24/99 1:49a Dave
250 * Fixed client-side afterburner stuttering. Added checkbox for no version
251 * checking on PXO join. Made button info passing more friendly between
254 * 160 8/22/99 5:53p Dave
255 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
256 * instead of ship designations for multiplayer players.
258 * 159 8/22/99 1:19p Dave
259 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
260 * which d3d cards are detected.
262 * 158 8/20/99 2:09p Dave
263 * PXO banner cycling.
265 * 157 8/19/99 10:59a Dave
266 * Packet loss detection.
268 * 156 8/19/99 10:12a Alanl
269 * preload mission-specific messages on machines greater than 48MB
271 * 155 8/16/99 4:04p Dave
272 * Big honking checkin.
274 * 154 8/11/99 5:54p Dave
275 * Fixed collision problem. Fixed standalone ghost problem.
277 * 153 8/10/99 7:59p Jefff
280 * 152 8/10/99 6:54p Dave
281 * Mad optimizations. Added paging to the nebula effect.
283 * 151 8/10/99 3:44p Jefff
284 * loads Intelligence information on startup
286 * 150 8/09/99 3:47p Dave
287 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
288 * non-nebula missions.
290 * 149 8/09/99 2:21p Andsager
291 * Fix patching from multiplayer direct to launcher update tab.
293 * 148 8/09/99 10:36a Dave
294 * Version info for game.
296 * 147 8/06/99 9:46p Dave
297 * Hopefully final changes for the demo.
299 * 146 8/06/99 3:34p Andsager
300 * Make title version info "(D)" -> "D" show up nicely
302 * 145 8/06/99 2:59p Adamp
303 * Fixed NT launcher/update problem.
305 * 144 8/06/99 1:52p Dave
306 * Bumped up MAX_BITMAPS for the demo.
308 * 143 8/06/99 12:17p Andsager
309 * Demo: down to just 1 demo dog
311 * 142 8/05/99 9:39p Dave
312 * Yet another new checksum.
314 * 141 8/05/99 6:19p Dave
315 * New demo checksums.
317 * 140 8/05/99 5:31p Andsager
318 * Up demo version 1.01
320 * 139 8/05/99 4:22p Andsager
321 * No time limit on upsell screens. Reverse order of display of upsell
324 * 138 8/05/99 4:17p Dave
325 * Tweaks to client interpolation.
327 * 137 8/05/99 3:52p Danw
329 * 136 8/05/99 3:01p Danw
331 * 135 8/05/99 2:43a Anoop
332 * removed duplicate definition.
334 * 134 8/05/99 2:13a Dave
337 * 133 8/05/99 2:05a Dave
340 * 132 8/05/99 1:22a Andsager
343 * 131 8/04/99 9:51p Andsager
344 * Add title screen to demo
346 * 130 8/04/99 6:47p Jefff
347 * fixed link error resulting from #ifdefs
349 * 129 8/04/99 6:26p Dave
350 * Updated ship tbl checksum.
352 * 128 8/04/99 5:40p Andsager
353 * Add multiple demo dogs
355 * 127 8/04/99 5:36p Andsager
356 * Show upsell screens at end of demo campaign before returning to main
359 * 126 8/04/99 11:42a Danw
360 * tone down EAX reverb
362 * 125 8/04/99 11:23a Dave
363 * Updated demo checksums.
365 * 124 8/03/99 11:02p Dave
366 * Maybe fixed sync problems in multiplayer.
368 * 123 8/03/99 6:21p Jefff
371 * 122 8/03/99 3:44p Andsager
372 * Launch laucher if trying to run FS without first having configured
375 * 121 8/03/99 12:45p Dave
378 * 120 8/02/99 9:13p Dave
381 * 119 7/30/99 10:31p Dave
382 * Added comm menu to the configurable hud files.
384 * 118 7/30/99 5:17p Andsager
385 * first fs2demo checksums
387 * 117 7/29/99 3:09p Anoop
389 * 116 7/29/99 12:05a Dave
390 * Nebula speed optimizations.
392 * 115 7/27/99 8:59a Andsager
393 * Make major, minor version consistent for all builds. Only show major
394 * and minor for launcher update window.
396 * 114 7/26/99 5:50p Dave
397 * Revised ingame join. Better? We'll see....
399 * 113 7/26/99 5:27p Andsager
400 * Add training mission as builtin to demo build
402 * 112 7/24/99 1:54p Dave
403 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
406 * 111 7/22/99 4:00p Dave
407 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
409 * 110 7/21/99 8:10p Dave
410 * First run of supernova effect.
412 * 109 7/20/99 1:49p Dave
413 * Peter Drake build. Fixed some release build warnings.
415 * 108 7/19/99 2:26p Andsager
416 * set demo multiplayer missions
418 * 107 7/18/99 5:19p Dave
419 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
421 * 106 7/16/99 1:50p Dave
422 * 8 bit aabitmaps. yay.
424 * 105 7/15/99 3:07p Dave
425 * 32 bit detection support. Mouse coord commandline.
427 * 104 7/15/99 2:13p Dave
428 * Added 32 bit detection.
430 * 103 7/15/99 9:20a Andsager
431 * FS2_DEMO initial checkin
433 * 102 7/14/99 11:02a Dave
434 * Skill level default back to easy. Blech.
436 * 101 7/09/99 5:54p Dave
437 * Seperated cruiser types into individual types. Added tons of new
438 * briefing icons. Campaign screen.
440 * 100 7/08/99 4:43p Andsager
441 * New check for sparky_hi and print if not found.
443 * 99 7/08/99 10:53a Dave
444 * New multiplayer interpolation scheme. Not 100% done yet, but still
445 * better than the old way.
447 * 98 7/06/99 4:24p Dave
448 * Mid-level checkin. Starting on some potentially cool multiplayer
451 * 97 7/06/99 3:35p Andsager
452 * Allow movie to play before red alert mission.
454 * 96 7/03/99 5:50p Dave
455 * Make rotated bitmaps draw properly in padlock views.
457 * 95 7/02/99 9:55p Dave
458 * Player engine wash sound.
460 * 94 7/02/99 4:30p Dave
461 * Much more sophisticated lightning support.
463 * 93 6/29/99 7:52p Dave
464 * Put in exception handling in FS2.
466 * 92 6/22/99 9:37p Dave
467 * Put in pof spewing.
469 * 91 6/16/99 4:06p Dave
470 * New pilot info popup. Added new draw-bitmap-as-poly function.
472 * 90 6/15/99 1:56p Andsager
473 * For release builds, allow start up in high res only with
476 * 89 6/15/99 9:34a Dave
477 * Fixed key checking in single threaded version of the stamp notification
480 * 88 6/09/99 2:55p Andsager
481 * Allow multiple asteroid subtypes (of large, medium, small) and follow
484 * 87 6/08/99 1:14a Dave
485 * Multi colored hud test.
487 * 86 6/04/99 9:52a Dave
488 * Fixed some rendering problems.
490 * 85 6/03/99 10:15p Dave
491 * Put in temporary main hall screen.
493 * 84 6/02/99 6:18p Dave
494 * Fixed TNT lockup problems! Wheeeee!
496 * 83 6/01/99 3:52p Dave
497 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
498 * dead popup, pxo find player popup, pxo private room popup.
500 * 82 5/26/99 1:28p Jasenw
501 * changed coords for loading ani
503 * 81 5/26/99 11:46a Dave
504 * Added ship-blasting lighting and made the randomization of lighting
505 * much more customizable.
507 * 80 5/24/99 5:45p Dave
508 * Added detail levels to the nebula, with a decent speedup. Split nebula
509 * lightning into its own section.
527 #include "systemvars.h"
532 #include "starfield.h"
533 #include "lighting.h"
538 #include "fireballs.h"
542 #include "floating.h"
543 #include "gamesequence.h"
545 #include "optionsmenu.h"
546 #include "playermenu.h"
547 #include "trainingmenu.h"
548 #include "techmenu.h"
551 #include "hudmessage.h"
553 #include "missiongoals.h"
554 #include "missionparse.h"
559 #include "multiutil.h"
560 #include "multimsgs.h"
564 #include "freespace.h"
565 #include "managepilot.h"
567 #include "contexthelp.h"
570 #include "missionbrief.h"
571 #include "missiondebrief.h"
573 #include "missionshipchoice.h"
575 #include "hudconfig.h"
576 #include "controlsconfig.h"
577 #include "missionmessage.h"
578 #include "missiontraining.h"
580 #include "hudtarget.h"
582 #include "eventmusic.h"
583 #include "animplay.h"
584 #include "missionweaponchoice.h"
585 #include "missionlog.h"
586 #include "audiostr.h"
588 #include "missioncampaign.h"
590 #include "missionhotkey.h"
591 #include "objectsnd.h"
592 #include "cmeasure.h"
594 #include "linklist.h"
595 #include "shockwave.h"
596 #include "afterburner.h"
601 #include "stand_gui.h"
602 #include "pcxutils.h"
603 #include "hudtargetbox.h"
604 #include "multi_xfer.h"
605 #include "hudescort.h"
606 #include "multiutil.h"
609 #include "multiteamselect.h"
612 #include "readyroom.h"
613 #include "mainhallmenu.h"
614 #include "multilag.h"
616 #include "particle.h"
618 #include "multi_ingame.h"
619 #include "snazzyui.h"
620 #include "asteroid.h"
621 #include "popupdead.h"
622 #include "multi_voice.h"
623 #include "missioncmdbrief.h"
624 #include "redalert.h"
625 #include "gameplayhelp.h"
626 #include "multilag.h"
627 #include "staticrand.h"
628 #include "multi_pmsg.h"
629 #include "levelpaging.h"
630 #include "observer.h"
631 #include "multi_pause.h"
632 #include "multi_endgame.h"
633 #include "cutscenes.h"
634 #include "multi_respawn.h"
636 #include "multi_obj.h"
637 #include "multi_log.h"
639 #include "localize.h"
640 #include "osregistry.h"
641 #include "barracks.h"
642 #include "missionpause.h"
644 #include "alphacolors.h"
645 #include "objcollide.h"
648 #include "neblightning.h"
649 #include "shipcontrails.h"
652 #include "multi_dogfight.h"
653 #include "multi_rate.h"
654 #include "muzzleflash.h"
658 #include "mainhalltemp.h"
659 #include "exceptionhandler.h"
663 #include "supernova.h"
664 #include "hudshield.h"
665 // #include "names.h"
667 #include "missionloopbrief.h"
671 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
677 // 1.00.04 5/26/98 MWA -- going final (12 pm)
678 // 1.00.03 5/26/98 MWA -- going final (3 am)
679 // 1.00.02 5/25/98 MWA -- going final
680 // 1.00.01 5/25/98 MWA -- going final
681 // 0.90 5/21/98 MWA -- getting ready for final.
682 // 0.10 4/9/98. Set by MK.
684 // Demo version: (obsolete since DEMO codebase split from tree)
685 // 0.03 4/10/98 AL. Interplay rev
686 // 0.02 4/8/98 MK. Increased when this system was modified.
687 // 0.01 4/7/98? AL. First release to Interplay QA.
690 // 1.00 5/28/98 AL. First release to Interplay QA.
692 void game_level_init(int seed = -1);
693 void game_post_level_init();
694 void game_do_frame();
695 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
696 void game_reset_time();
697 void game_show_framerate(); // draws framerate in lower right corner
699 int Game_no_clear = 0;
701 int Pofview_running = 0;
702 int Nebedit_running = 0;
704 typedef struct big_expl_flash {
705 float max_flash_intensity; // max intensity
706 float cur_flash_intensity; // cur intensity
707 int flash_start; // start time
710 #define FRAME_FILTER 16
712 #define DEFAULT_SKILL_LEVEL 1
713 int Game_skill_level = DEFAULT_SKILL_LEVEL;
715 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
716 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
718 #define EXE_FNAME ("fs2.exe")
719 #define LAUNCHER_FNAME ("freespace2.exe")
721 // JAS: Code for warphole camera.
722 // Needs to be cleaned up.
723 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
724 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
725 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
726 matrix Camera_orient = IDENTITY_MATRIX;
727 float Camera_damping = 1.0f;
728 float Camera_time = 0.0f;
729 float Warpout_time = 0.0f;
730 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
731 int Warpout_sound = -1;
733 int Use_joy_mouse = 0;
734 int Use_palette_flash = 1;
736 int Use_fullscreen_at_startup = 0;
738 int Show_area_effect = 0;
739 object *Last_view_target = NULL;
741 int dogfight_blown = 0;
744 float frametimes[FRAME_FILTER];
745 float frametotal = 0.0f;
749 int Show_framerate = os_config_read_uint( NULL, "ShowFPS", 0 );
751 int Show_framerate = 1;
754 int Framerate_cap = 120;
757 int Show_target_debug_info = 0;
758 int Show_target_weapons = 0;
762 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
765 int Debug_octant = -1;
767 fix Game_time_compression = F1_0;
769 // if the ships.tbl the player has is valid
770 int Game_ships_tbl_valid = 0;
772 // if the weapons.tbl the player has is valid
773 int Game_weapons_tbl_valid = 0;
777 extern int Player_attacking_enabled;
781 int Pre_player_entry;
783 int Fred_running = 0;
784 char Game_current_mission_filename[MAX_FILENAME_LEN];
785 int game_single_step = 0;
786 int last_single_step=0;
788 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
789 extern int MSG_WINDOW_Y_START;
790 extern int MSG_WINDOW_HEIGHT;
792 int game_zbuffer = 1;
793 //static int Game_music_paused;
794 static int Game_paused;
798 #define EXPIRE_BAD_CHECKSUM 1
799 #define EXPIRE_BAD_TIME 2
801 extern void ssm_init();
802 extern void ssm_level_init();
803 extern void ssm_process();
805 // static variable to contain the time this version was built
806 // commented out for now until
807 // I figure out how to get the username into the file
808 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
810 // defines and variables used for dumping frame for making trailers.
812 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
813 int Debug_dump_trigger = 0;
814 int Debug_dump_frame_count;
815 int Debug_dump_frame_num = 0;
816 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
819 // amount of time to wait after the player has died before we display the death died popup
820 #define PLAYER_DIED_POPUP_WAIT 2500
821 int Player_died_popup_wait = -1;
822 int Player_multi_died_check = -1;
824 // builtin mission list stuff
826 int Game_builtin_mission_count = 6;
827 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
828 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
829 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
830 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
831 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
832 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
833 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
835 #elif defined(PD_BUILD)
836 int Game_builtin_mission_count = 4;
837 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
838 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
839 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
840 { "sm1-01", (FSB_FROM_VOLITION), "" },
841 { "sm1-05", (FSB_FROM_VOLITION), "" },
843 #elif defined(MULTIPLAYER_BETA)
844 int Game_builtin_mission_count = 17;
845 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
847 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
848 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
849 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
852 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
855 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
858 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
859 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
860 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
861 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
862 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
863 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
865 #elif defined(OEM_BUILD)
866 int Game_builtin_mission_count = 17;
867 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
868 // oem version - act 1 only
869 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
872 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
873 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
874 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
875 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
876 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
877 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
878 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
879 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
880 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
881 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
882 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
883 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
884 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
885 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
886 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
887 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
890 int Game_builtin_mission_count = 92;
891 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
892 // single player campaign
893 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
896 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
899 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
900 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
901 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
902 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
903 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
904 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
905 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
906 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
907 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
908 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
909 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
910 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
911 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
912 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
913 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
914 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
917 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
922 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
925 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
926 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
929 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
930 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
931 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
932 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
933 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
934 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
935 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
936 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
937 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
938 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
939 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
940 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
942 // multiplayer missions
945 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
987 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
988 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
989 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
990 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
991 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
992 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
993 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
994 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
995 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
998 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
999 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1000 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1001 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1002 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1007 // Internal function prototypes
1008 void game_maybe_draw_mouse(float frametime);
1009 void init_animating_pointer();
1010 void load_animating_pointer(char *filename, int dx, int dy);
1011 void unload_animating_pointer();
1012 void game_do_training_checks();
1013 void game_shutdown(void);
1014 void game_show_event_debug(float frametime);
1015 void game_event_debug_init();
1017 void demo_upsell_show_screens();
1018 void game_start_subspace_ambient_sound();
1019 void game_stop_subspace_ambient_sound();
1020 void verify_ships_tbl();
1021 void verify_weapons_tbl();
1022 void display_title_screen();
1024 // loading background filenames
1025 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1026 "LoadingBG", // GR_640
1027 "2_LoadingBG" // GR_1024
1031 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1032 "Loading.ani", // GR_640
1033 "2_Loading.ani" // GR_1024
1036 #if defined(FS2_DEMO)
1037 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1041 #elif defined(OEM_BUILD)
1042 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1049 char Game_CDROM_dir[MAX_PATH_LEN];
1052 // How much RAM is on this machine. Set in WinMain
1053 uint Freespace_total_ram = 0;
1056 float Game_flash_red = 0.0f;
1057 float Game_flash_green = 0.0f;
1058 float Game_flash_blue = 0.0f;
1059 float Sun_spot = 0.0f;
1060 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1062 // game shudder stuff (in ms)
1063 int Game_shudder_time = -1;
1064 int Game_shudder_total = 0;
1065 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1068 sound_env Game_sound_env;
1069 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1070 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1072 int Game_sound_env_update_timestamp;
1074 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1077 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1079 fs_builtin_mission *game_find_builtin_mission(char *filename)
1083 // look through all existing builtin missions
1084 for(idx=0; idx<Game_builtin_mission_count; idx++){
1085 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1086 return &Game_builtin_mission_list[idx];
1094 int game_get_default_skill_level()
1096 return DEFAULT_SKILL_LEVEL;
1100 void game_flash_reset()
1102 Game_flash_red = 0.0f;
1103 Game_flash_green = 0.0f;
1104 Game_flash_blue = 0.0f;
1106 Big_expl_flash.max_flash_intensity = 0.0f;
1107 Big_expl_flash.cur_flash_intensity = 0.0f;
1108 Big_expl_flash.flash_start = 0;
1111 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1112 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1114 void game_framerate_check_init()
1116 // zero critical time
1117 Gf_critical_time = 0.0f;
1120 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1121 // if this is a glide card
1122 if(gr_screen.mode == GR_GLIDE){
1124 extern GrHwConfiguration hwconfig;
1127 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1128 Gf_critical = 15.0f;
1132 Gf_critical = 10.0f;
1137 Gf_critical = 15.0f;
1140 // d3d. only care about good cards here I guess (TNT)
1142 Gf_critical = 15.0f;
1145 // if this is a glide card
1146 if(gr_screen.mode == GR_GLIDE){
1148 extern GrHwConfiguration hwconfig;
1151 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1152 Gf_critical = 25.0f;
1156 Gf_critical = 20.0f;
1161 Gf_critical = 25.0f;
1164 // d3d. only care about good cards here I guess (TNT)
1166 Gf_critical = 25.0f;
1171 extern float Framerate;
1172 void game_framerate_check()
1176 // if the current framerate is above the critical level, add frametime
1177 if(Framerate >= Gf_critical){
1178 Gf_critical_time += flFrametime;
1181 if(!Show_framerate){
1185 // display if we're above the critical framerate
1186 if(Framerate < Gf_critical){
1187 gr_set_color_fast(&Color_bright_red);
1188 gr_string(200, y_start, "Framerate warning");
1193 // display our current pct of good frametime
1194 if(f2fl(Missiontime) >= 0.0f){
1195 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1198 gr_set_color_fast(&Color_bright_green);
1200 gr_set_color_fast(&Color_bright_red);
1203 gr_printf(200, y_start, "%d%%", (int)pct);
1210 // Adds a flash effect. These can be positive or negative.
1211 // The range will get capped at around -1 to 1, so stick
1212 // with a range like that.
1213 void game_flash( float r, float g, float b )
1215 Game_flash_red += r;
1216 Game_flash_green += g;
1217 Game_flash_blue += b;
1219 if ( Game_flash_red < -1.0f ) {
1220 Game_flash_red = -1.0f;
1221 } else if ( Game_flash_red > 1.0f ) {
1222 Game_flash_red = 1.0f;
1225 if ( Game_flash_green < -1.0f ) {
1226 Game_flash_green = -1.0f;
1227 } else if ( Game_flash_green > 1.0f ) {
1228 Game_flash_green = 1.0f;
1231 if ( Game_flash_blue < -1.0f ) {
1232 Game_flash_blue = -1.0f;
1233 } else if ( Game_flash_blue > 1.0f ) {
1234 Game_flash_blue = 1.0f;
1239 // Adds a flash for Big Ship explosions
1240 // cap range from 0 to 1
1241 void big_explosion_flash(float flash)
1243 Big_expl_flash.flash_start = timestamp(1);
1247 } else if (flash < 0.0f) {
1251 Big_expl_flash.max_flash_intensity = flash;
1252 Big_expl_flash.cur_flash_intensity = 0.0f;
1255 // Amount to diminish palette towards normal, per second.
1256 #define DIMINISH_RATE 0.75f
1257 #define SUN_DIMINISH_RATE 6.00f
1261 float sn_glare_scale = 1.7f;
1264 dc_get_arg(ARG_FLOAT);
1265 sn_glare_scale = Dc_arg_float;
1268 float Supernova_last_glare = 0.0f;
1269 void game_sunspot_process(float frametime)
1273 float Sun_spot_goal = 0.0f;
1276 sn_stage = supernova_active();
1278 // sunspot differently based on supernova stage
1280 // approaching. player still in control
1283 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1286 light_get_global_dir(&light_dir, 0);
1288 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1291 // scale it some more
1292 dot = dot * (0.5f + (pct * 0.5f));
1295 Sun_spot_goal += (dot * sn_glare_scale);
1298 // draw the sun glow
1299 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1300 // draw the glow for this sun
1301 stars_draw_sun_glow(0);
1304 Supernova_last_glare = Sun_spot_goal;
1307 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1310 Sun_spot_goal = 0.9f;
1311 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1313 if(Sun_spot_goal > 1.0f){
1314 Sun_spot_goal = 1.0f;
1317 Sun_spot_goal *= sn_glare_scale;
1318 Supernova_last_glare = Sun_spot_goal;
1321 // fade to white. display dead popup
1324 Supernova_last_glare += (2.0f * flFrametime);
1325 if(Supernova_last_glare > 2.0f){
1326 Supernova_last_glare = 2.0f;
1329 Sun_spot_goal = Supernova_last_glare;
1336 // check sunspots for all suns
1337 n_lights = light_get_global_count();
1340 for(idx=0; idx<n_lights; idx++){
1341 //(vector *eye_pos, matrix *eye_orient)
1342 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1345 light_get_global_dir(&light_dir, idx);
1347 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1349 Sun_spot_goal += (float)pow(dot,85.0f);
1351 // draw the glow for this sun
1352 stars_draw_sun_glow(idx);
1354 Sun_spot_goal = 0.0f;
1360 Sun_spot_goal = 0.0f;
1364 float dec_amount = frametime*SUN_DIMINISH_RATE;
1366 if ( Sun_spot < Sun_spot_goal ) {
1367 Sun_spot += dec_amount;
1368 if ( Sun_spot > Sun_spot_goal ) {
1369 Sun_spot = Sun_spot_goal;
1371 } else if ( Sun_spot > Sun_spot_goal ) {
1372 Sun_spot -= dec_amount;
1373 if ( Sun_spot < Sun_spot_goal ) {
1374 Sun_spot = Sun_spot_goal;
1380 // Call once a frame to diminish the
1381 // flash effect to 0.
1382 void game_flash_diminish(float frametime)
1384 float dec_amount = frametime*DIMINISH_RATE;
1386 if ( Game_flash_red > 0.0f ) {
1387 Game_flash_red -= dec_amount;
1388 if ( Game_flash_red < 0.0f )
1389 Game_flash_red = 0.0f;
1391 Game_flash_red += dec_amount;
1392 if ( Game_flash_red > 0.0f )
1393 Game_flash_red = 0.0f;
1396 if ( Game_flash_green > 0.0f ) {
1397 Game_flash_green -= dec_amount;
1398 if ( Game_flash_green < 0.0f )
1399 Game_flash_green = 0.0f;
1401 Game_flash_green += dec_amount;
1402 if ( Game_flash_green > 0.0f )
1403 Game_flash_green = 0.0f;
1406 if ( Game_flash_blue > 0.0f ) {
1407 Game_flash_blue -= dec_amount;
1408 if ( Game_flash_blue < 0.0f )
1409 Game_flash_blue = 0.0f;
1411 Game_flash_blue += dec_amount;
1412 if ( Game_flash_blue > 0.0f )
1413 Game_flash_blue = 0.0f;
1416 // update big_explosion_cur_flash
1417 #define TIME_UP 1500
1418 #define TIME_DOWN 2500
1419 int duration = TIME_UP + TIME_DOWN;
1420 int time = timestamp_until(Big_expl_flash.flash_start);
1421 if (time > -duration) {
1423 if (time < TIME_UP) {
1424 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1427 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1431 if ( Use_palette_flash ) {
1433 // static int or=0, og=0, ob=0;
1435 // Change the 200 to change the color range of colors.
1436 r = fl2i( Game_flash_red*128.0f );
1437 g = fl2i( Game_flash_green*128.0f );
1438 b = fl2i( Game_flash_blue*128.0f );
1440 if ( Sun_spot > 0.0f ) {
1441 r += fl2i(Sun_spot*128.0f);
1442 g += fl2i(Sun_spot*128.0f);
1443 b += fl2i(Sun_spot*128.0f);
1446 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1447 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1448 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1449 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1452 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1453 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1454 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1456 if ( (r!=0) || (g!=0) || (b!=0) ) {
1457 gr_flash( r, g, b );
1459 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1470 void game_level_close()
1472 // De-Initialize the game subsystems
1473 message_mission_shutdown();
1474 event_music_level_close();
1475 game_stop_looped_sounds();
1477 obj_snd_level_close(); // uninit object-linked persistant sounds
1478 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1479 anim_level_close(); // stop and clean up any anim instances
1480 shockwave_level_close();
1481 fireball_level_close();
1483 mission_event_shutdown();
1484 asteroid_level_close();
1485 model_cache_reset(); // Reset/free all the model caching stuff
1486 flak_level_close(); // unload flak stuff
1487 neb2_level_close(); // shutdown gaseous nebula stuff
1490 mflash_level_close();
1492 audiostream_unpause_all();
1497 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1498 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1499 void game_level_init(int seed)
1501 // seed the random number generator
1503 // if no seed was passed, seed the generator either from the time value, or from the
1504 // netgame security flags -- ensures that all players in multiplayer game will have the
1505 // same randon number sequence (with static rand functions)
1506 if ( Game_mode & GM_NORMAL ) {
1507 Game_level_seed = time(NULL);
1509 Game_level_seed = Netgame.security;
1512 // mwa 9/17/98 -- maybe this assert isn't needed????
1513 Assert( !(Game_mode & GM_MULTIPLAYER) );
1514 Game_level_seed = seed;
1516 srand( Game_level_seed );
1518 // semirand function needs to get re-initted every time in multiplayer
1519 if ( Game_mode & GM_MULTIPLAYER ){
1525 Key_normal_game = (Game_mode & GM_NORMAL);
1528 Game_shudder_time = -1;
1530 // Initialize the game subsystems
1531 // timestamp_reset(); // Must be inited before everything else
1533 game_reset_time(); // resets time, and resets saved time too
1535 obj_init(); // Must be inited before the other systems
1536 model_free_all(); // Free all existing models
1537 mission_brief_common_init(); // Free all existing briefing/debriefing text
1538 weapon_level_init();
1539 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1541 player_level_init();
1542 shipfx_flash_init(); // Init the ship gun flash system.
1543 game_flash_reset(); // Reset the flash effect
1544 particle_init(); // Reset the particle system
1548 shield_hit_init(); // Initialize system for showing shield hits
1549 radar_mission_init();
1550 mission_init_goals();
1553 obj_snd_level_init(); // init object-linked persistant sounds
1555 shockwave_level_init();
1556 afterburner_level_init();
1557 scoring_level_init( &Player->stats );
1559 asteroid_level_init();
1560 control_config_clear_used_status();
1561 collide_ship_ship_sounds_init();
1563 Pre_player_entry = 1; // Means the player has not yet entered.
1564 Entry_delay_time = 0; // Could get overwritten in mission read.
1565 fireball_preload(); // page in warphole bitmaps
1567 flak_level_init(); // initialize flak - bitmaps, etc
1568 ct_level_init(); // initialize ships contrails, etc
1569 awacs_level_init(); // initialize AWACS
1570 beam_level_init(); // initialize beam weapons
1571 mflash_level_init();
1573 supernova_level_init();
1575 // multiplayer dogfight hack
1578 shipfx_engine_wash_level_init();
1582 Last_view_target = NULL;
1587 // campaign wasn't ended
1588 Campaign_ended_in_mission = 0;
1591 // called when a mission is over -- does server specific stuff.
1592 void freespace_stop_mission()
1595 Game_mode &= ~GM_IN_MISSION;
1598 // called at frame interval to process networking stuff
1599 void game_do_networking()
1601 Assert( Net_player != NULL );
1602 if (!(Game_mode & GM_MULTIPLAYER)){
1606 // see if this player should be reading/writing data. Bit is set when at join
1607 // screen onward until quits back to main menu.
1608 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1612 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1615 multi_pause_do_frame();
1620 // Loads the best palette for this level, based
1621 // on nebula color and hud color. You could just call palette_load_table with
1622 // the appropriate filename, but who wants to do that.
1623 void game_load_palette()
1625 char palette_filename[1024];
1627 // We only use 3 hud colors right now
1628 // Assert( HUD_config.color >= 0 );
1629 // Assert( HUD_config.color <= 2 );
1631 Assert( Mission_palette >= 0 );
1632 Assert( Mission_palette <= 98 );
1634 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1635 strcpy( palette_filename, NOX("gamepalette-subspace") );
1637 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1640 mprintf(( "Loading palette %s\n", palette_filename ));
1642 // palette_load_table(palette_filename);
1645 void game_post_level_init()
1647 // Stuff which gets called after mission is loaded. Because player isn't created until
1648 // after mission loads, some things must get initted after the level loads
1650 model_level_post_init();
1653 hud_setup_escort_list();
1654 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1660 game_event_debug_init();
1663 training_mission_init();
1664 asteroid_create_all();
1666 game_framerate_check_init();
1670 // An estimate as to how high the count passed to game_loading_callback will go.
1671 // This is just a guess, it seems to always be about the same. The count is
1672 // proportional to the code being executed, not the time, so this works good
1673 // for a bar, assuming the code does about the same thing each time you
1674 // load a level. You can find this value by looking at the return value
1675 // of game_busy_callback(NULL), which I conveniently print out to the
1676 // debug output window with the '=== ENDING LOAD ==' stuff.
1677 //#define COUNT_ESTIMATE 3706
1678 #define COUNT_ESTIMATE 1111
1680 int Game_loading_callback_inited = 0;
1682 int Game_loading_background = -1;
1683 anim * Game_loading_ani = NULL;
1684 anim_instance *Game_loading_ani_instance;
1685 int Game_loading_frame=-1;
1687 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1696 // This gets called 10x per second and count is the number of times
1697 // game_busy() has been called since the current callback function
1699 void game_loading_callback(int count)
1701 game_do_networking();
1703 Assert( Game_loading_callback_inited==1 );
1704 Assert( Game_loading_ani != NULL );
1706 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1707 if ( framenum > Game_loading_ani->total_frames-1 ) {
1708 framenum = Game_loading_ani->total_frames-1;
1709 } else if ( framenum < 0 ) {
1714 while ( Game_loading_frame < framenum ) {
1715 Game_loading_frame++;
1716 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1720 if ( cbitmap > -1 ) {
1721 if ( Game_loading_background > -1 ) {
1722 gr_set_bitmap( Game_loading_background );
1726 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1727 gr_set_bitmap( cbitmap );
1728 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1730 bm_release(cbitmap);
1736 void game_loading_callback_init()
1738 Assert( Game_loading_callback_inited==0 );
1740 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1741 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1744 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1745 Assert( Game_loading_ani != NULL );
1746 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1747 Assert( Game_loading_ani_instance != NULL );
1748 Game_loading_frame = -1;
1750 Game_loading_callback_inited = 1;
1752 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1757 void game_loading_callback_close()
1759 Assert( Game_loading_callback_inited==1 );
1761 // Make sure bar shows all the way over.
1762 game_loading_callback(COUNT_ESTIMATE);
1764 int real_count = game_busy_callback( NULL );
1767 Game_loading_callback_inited = 0;
1770 mprintf(( "=================== ENDING LOAD ================\n" ));
1771 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1772 mprintf(( "================================================\n" ));
1774 // to remove warnings in release build
1778 free_anim_instance(Game_loading_ani_instance);
1779 Game_loading_ani_instance = NULL;
1780 anim_free(Game_loading_ani);
1781 Game_loading_ani = NULL;
1783 bm_release( Game_loading_background );
1784 common_free_interface_palette(); // restore game palette
1785 Game_loading_background = -1;
1787 gr_set_font( FONT1 );
1790 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1792 void game_maybe_update_sound_environment()
1794 // do nothing for now
1797 // Assign the sound environment for the game, based on the current mission
1799 void game_assign_sound_environment()
1802 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1803 Game_sound_env.id = SND_ENV_DRUGGED;
1804 Game_sound_env.volume = 0.800f;
1805 Game_sound_env.damping = 1.188f;
1806 Game_sound_env.decay = 6.392f;
1808 } else if (Num_asteroids > 30) {
1809 Game_sound_env.id = SND_ENV_AUDITORIUM;
1810 Game_sound_env.volume = 0.603f;
1811 Game_sound_env.damping = 0.5f;
1812 Game_sound_env.decay = 4.279f;
1815 Game_sound_env = Game_default_sound_env;
1819 Game_sound_env = Game_default_sound_env;
1820 Game_sound_env_update_timestamp = timestamp(1);
1823 // function which gets called before actually entering the mission. It is broken down into a funciton
1824 // since it will get called in one place from a single player game and from another place for
1825 // a multiplayer game
1826 void freespace_mission_load_stuff()
1828 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1829 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1830 if(!(Game_mode & GM_STANDALONE_SERVER)){
1832 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1834 game_loading_callback_init();
1836 event_music_level_init(); // preloads the first 2 seconds for each event music track
1839 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1842 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1845 ship_assign_sound_all(); // assign engine sounds to ships
1846 game_assign_sound_environment(); // assign the sound environment for this mission
1849 // call function in missionparse.cpp to fixup player/ai stuff.
1850 mission_parse_fixup_players();
1853 // Load in all the bitmaps for this level
1858 game_loading_callback_close();
1860 // the only thing we need to call on the standalone for now.
1862 // call function in missionparse.cpp to fixup player/ai stuff.
1863 mission_parse_fixup_players();
1865 // Load in all the bitmaps for this level
1871 uint load_mission_load;
1872 uint load_post_level_init;
1873 uint load_mission_stuff;
1875 // tells the server to load the mission and initialize structures
1876 int game_start_mission()
1878 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1880 load_gl_init = time(NULL);
1882 load_gl_init = time(NULL) - load_gl_init;
1884 if (Game_mode & GM_MULTIPLAYER) {
1885 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1887 // clear multiplayer stats
1888 init_multiplayer_stats();
1891 load_mission_load = time(NULL);
1892 if (mission_load()) {
1893 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1894 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1895 gameseq_post_event(GS_EVENT_MAIN_MENU);
1897 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1902 load_mission_load = time(NULL) - load_mission_load;
1904 // If this is a red alert mission in campaign mode, bash wingman status
1905 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1906 red_alert_bash_wingman_status();
1909 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1910 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1911 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1912 // game_load_palette();
1915 load_post_level_init = time(NULL);
1916 game_post_level_init();
1917 load_post_level_init = time(NULL) - load_post_level_init;
1921 void Do_model_timings_test();
1922 Do_model_timings_test();
1926 load_mission_stuff = time(NULL);
1927 freespace_mission_load_stuff();
1928 load_mission_stuff = time(NULL) - load_mission_stuff;
1933 int Interface_framerate = 0;
1936 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1937 DCF_BOOL( show_framerate, Show_framerate )
1938 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1939 DCF_BOOL( show_target_weapons, Show_target_weapons )
1940 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1941 DCF_BOOL( sound, Sound_enabled )
1942 DCF_BOOL( zbuffer, game_zbuffer )
1943 DCF_BOOL( shield_system, New_shield_system )
1944 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1945 DCF_BOOL( player_attacking, Player_attacking_enabled )
1946 DCF_BOOL( show_waypoints, Show_waypoints )
1947 DCF_BOOL( show_area_effect, Show_area_effect )
1948 DCF_BOOL( show_net_stats, Show_net_stats )
1949 DCF_BOOL( log, Log_debug_output_to_file )
1950 DCF_BOOL( training_msg_method, Training_msg_method )
1951 DCF_BOOL( show_player_pos, Show_player_pos )
1952 DCF_BOOL(i_framerate, Interface_framerate )
1954 DCF(show_mem,"Toggles showing mem usage")
1957 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1958 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1959 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1960 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1966 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1968 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1969 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1973 DCF(show_cpu,"Toggles showing cpu usage")
1976 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1977 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1978 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1979 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1985 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1987 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1988 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1995 // AL 4-8-98: always allow players to display their framerate
1998 DCF_BOOL( show_framerate, Show_framerate )
2005 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2008 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2009 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2010 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2011 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2013 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" );
2014 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2016 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2019 DCF(palette_flash,"Toggles palette flash effect on/off")
2022 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2023 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2024 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2025 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2027 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2028 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2031 int Use_low_mem = 0;
2033 DCF(low_mem,"Uses low memory settings regardless of RAM")
2036 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2037 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2038 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2039 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2041 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2042 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2044 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2050 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2053 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2054 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2055 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2056 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2058 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2059 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2060 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2064 int Framerate_delay = 0;
2066 float Freespace_gamma = 1.0f;
2068 DCF(gamma,"Sets Gamma factor")
2071 dc_get_arg(ARG_FLOAT|ARG_NONE);
2072 if ( Dc_arg_type & ARG_FLOAT ) {
2073 Freespace_gamma = Dc_arg_float;
2075 dc_printf( "Gamma reset to 1.0f\n" );
2076 Freespace_gamma = 1.0f;
2078 if ( Freespace_gamma < 0.1f ) {
2079 Freespace_gamma = 0.1f;
2080 } else if ( Freespace_gamma > 5.0f ) {
2081 Freespace_gamma = 5.0f;
2083 gr_set_gamma(Freespace_gamma);
2085 char tmp_gamma_string[32];
2086 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2087 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2091 dc_printf( "Usage: gamma <float>\n" );
2092 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2093 Dc_status = 0; // don't print status if help is printed. Too messy.
2097 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2106 Game_current_mission_filename[0] = 0;
2108 // seed the random number generator
2109 Game_init_seed = time(NULL);
2110 srand( Game_init_seed );
2112 Framerate_delay = 0;
2118 extern void bm_init();
2124 // Initialize the timer before the os
2132 GetCurrentDirectory(1024, whee);
2135 getcwd (whee, 1024);
2138 strcat(whee, EXE_FNAME);
2140 //Initialize the libraries
2141 s1 = timer_get_milliseconds();
2142 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2145 e1 = timer_get_milliseconds();
2147 // time a bunch of cfopens
2149 s2 = timer_get_milliseconds();
2151 for(int idx=0; idx<10000; idx++){
2152 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2157 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2159 e2 = timer_get_milliseconds();
2162 if (Is_standalone) {
2163 std_init_standalone();
2165 os_init( Osreg_class_name, Osreg_app_name );
2166 os_set_title(Osreg_title);
2169 // initialize localization module. Make sure this is down AFTER initialzing OS.
2170 // int t1 = timer_get_milliseconds();
2173 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2175 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2178 // verify that he has a valid weapons.tbl
2179 verify_weapons_tbl();
2182 // setup the default osreg values if they don't exist
2186 // Output version numbers to registry for auto patching purposes
2187 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2188 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2189 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2191 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2192 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2193 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2196 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2200 Asteroids_enabled = 1;
2203 /////////////////////////////
2205 /////////////////////////////
2210 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2211 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2213 if (!stricmp(ptr, NOX("no sound"))) {
2214 Cmdline_freespace_no_sound = 1;
2216 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2218 } else if (!stricmp(ptr, NOX("EAX"))) {
2223 if (!Is_standalone) {
2224 snd_init(use_a3d, use_eax);
2226 /////////////////////////////
2228 /////////////////////////////
2230 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2233 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);
2235 // fire up the UpdateLauncher executable
2237 PROCESS_INFORMATION pi;
2239 memset( &si, 0, sizeof(STARTUPINFO) );
2242 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2243 NULL, // pointer to command line string
2244 NULL, // pointer to process security attributes
2245 NULL, // pointer to thread security attributes
2246 FALSE, // handle inheritance flag
2247 CREATE_DEFAULT_ERROR_MODE, // creation flags
2248 NULL, // pointer to new environment block
2249 NULL, // pointer to current directory name
2250 &si, // pointer to STARTUPINFO
2251 &pi // pointer to PROCESS_INFORMATION
2254 // If the Launcher could not be started up, let the user know
2256 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2265 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2267 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);
2275 // check for hi res pack file
2276 int has_sparky_hi = 0;
2278 // check if sparky_hi exists -- access mode 0 means does file exist
2281 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2284 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2287 // see if we've got 32 bit in the string
2288 if(strstr(ptr, "32 bit")){
2295 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2297 // always 640 for E3
2298 gr_init(GR_640, GR_GLIDE);
2300 // regular or hi-res ?
2302 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2304 if(strstr(ptr, NOX("(1024x768)"))){
2306 gr_init(GR_1024, GR_GLIDE);
2308 gr_init(GR_640, GR_GLIDE);
2311 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2313 // always 640 for E3
2315 gr_init(GR_640, GR_DIRECT3D, depth);
2317 // regular or hi-res ?
2319 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2321 if(strstr(ptr, NOX("(1024x768)"))){
2325 gr_init(GR_1024, GR_DIRECT3D, depth);
2329 gr_init(GR_640, GR_DIRECT3D, depth);
2335 if ( Use_fullscreen_at_startup && !Is_standalone) {
2336 gr_init(GR_640, GR_DIRECTDRAW);
2338 gr_init(GR_640, GR_SOFTWARE);
2341 if ( !Is_standalone ) {
2342 gr_init(GR_640, GR_DIRECTDRAW);
2344 gr_init(GR_640, GR_SOFTWARE);
2349 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2350 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2351 gr_init(GR_1024, GR_OPENGL);
2353 gr_init(GR_640, GR_OPENGL);
2357 gr_init(GR_640, GR_SOFTWARE);
2362 extern int Gr_inited;
2363 if(trying_d3d && !Gr_inited){
2365 extern char Device_init_error[512];
2366 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2375 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2376 Freespace_gamma = (float)atof(ptr);
2377 if ( Freespace_gamma == 0.0f ) {
2378 Freespace_gamma = 1.80f;
2379 } else if ( Freespace_gamma < 0.1f ) {
2380 Freespace_gamma = 0.1f;
2381 } else if ( Freespace_gamma > 5.0f ) {
2382 Freespace_gamma = 5.0f;
2384 char tmp_gamma_string[32];
2385 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2386 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2388 gr_set_gamma(Freespace_gamma);
2390 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2393 display_title_screen();
2397 // attempt to load up master tracker registry info (login and password)
2398 Multi_tracker_id = -1;
2400 // pxo login and password
2401 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2403 nprintf(("Network","Error reading in PXO login data\n"));
2404 strcpy(Multi_tracker_login,"");
2406 strcpy(Multi_tracker_login,ptr);
2408 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2410 nprintf(("Network","Error reading PXO password\n"));
2411 strcpy(Multi_tracker_passwd,"");
2413 strcpy(Multi_tracker_passwd,ptr);
2416 // pxo squad name and password
2417 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2419 nprintf(("Network","Error reading in PXO squad name\n"));
2420 strcpy(Multi_tracker_squad_name, "");
2422 strcpy(Multi_tracker_squad_name, ptr);
2425 // If less than 48MB of RAM, use low memory model.
2428 (Freespace_total_ram < 48*1024*1024) ||
2431 mprintf(( "Using normal memory settings...\n" ));
2432 bm_set_low_mem(1); // Use every other frame of bitmaps
2434 mprintf(( "Using high memory settings...\n" ));
2435 bm_set_low_mem(0); // Use all frames of bitmaps
2438 // load non-darkening pixel defs
2439 palman_load_pixels();
2441 // hud shield icon stuff
2442 hud_shield_game_init();
2444 control_config_common_init(); // sets up localization stuff in the control config
2450 gamesnd_parse_soundstbl();
2455 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2460 player_controls_init();
2463 //if(!Is_standalone){
2471 ship_init(); // read in ships.tbl
2473 mission_campaign_init(); // load in the default campaign
2475 // navmap_init(); // init the navigation map system
2476 context_help_init();
2477 techroom_intel_init(); // parse species.tbl, load intel info
2479 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2480 init_animating_pointer();
2482 mission_brief_common_init(); // Mark all the briefing structures as empty.
2483 gr_font_init(); // loads up all fonts
2485 neb2_init(); // fullneb stuff
2489 player_tips_init(); // helpful tips
2492 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2493 pilot_load_pic_list();
2494 pilot_load_squad_pic_list();
2496 load_animating_pointer(NOX("cursor"), 0, 0);
2498 // initialize alpha colors
2499 alpha_colors_init();
2502 // Game_music_paused = 0;
2509 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2510 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2512 mprintf(("cfile_init() took %d\n", e1 - s1));
2513 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2516 char transfer_text[128];
2518 float Start_time = 0.0f;
2520 float Framerate = 0.0f;
2522 float Timing_total = 0.0f;
2523 float Timing_render2 = 0.0f;
2524 float Timing_render3 = 0.0f;
2525 float Timing_flip = 0.0f;
2526 float Timing_clear = 0.0f;
2528 MONITOR(NumPolysDrawn);
2534 void game_get_framerate()
2536 char text[128] = "";
2538 if ( frame_int == -1 ) {
2540 for (i=0; i<FRAME_FILTER; i++ ) {
2541 frametimes[i] = 0.0f;
2546 frametotal -= frametimes[frame_int];
2547 frametotal += flFrametime;
2548 frametimes[frame_int] = flFrametime;
2549 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2551 if ( frametotal != 0.0 ) {
2552 if ( Framecount >= FRAME_FILTER )
2553 Framerate = FRAME_FILTER / frametotal;
2555 Framerate = Framecount / frametotal;
2556 sprintf( text, NOX("FPS: %.1f"), Framerate );
2558 sprintf( text, NOX("FPS: ?") );
2562 if (Show_framerate) {
2563 gr_set_color_fast(&HUD_color_debug);
2564 gr_string( 570, 2, text );
2568 void game_show_framerate()
2572 cur_time = f2fl(timer_get_approx_seconds());
2573 if (cur_time - Start_time > 30.0f) {
2574 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2575 Start_time += 1000.0f;
2578 //mprintf(( "%s\n", text ));
2581 if ( Debug_dump_frames )
2585 // possibly show control checking info
2586 control_check_indicate();
2588 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2589 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2590 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2591 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2594 if ( Show_cpu == 1 ) {
2599 dy = gr_get_font_height() + 1;
2601 gr_set_color_fast(&HUD_color_debug);
2605 extern int D3D_textures_in;
2606 extern int D3D_textures_in_frame;
2607 extern int Glide_textures_in;
2608 extern int Glide_textures_in_frame;
2609 extern int Glide_explosion_vram;
2610 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2612 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2614 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2618 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2620 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2622 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2624 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2626 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2631 extern int Num_pairs; // Number of object pairs that were checked.
2632 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2635 extern int Num_pairs_checked; // What percent of object pairs were checked.
2636 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2638 Num_pairs_checked = 0;
2642 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2645 if ( Timing_total > 0.01f ) {
2646 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2648 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2650 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2652 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2654 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2664 dy = gr_get_font_height() + 1;
2666 gr_set_color_fast(&HUD_color_debug);
2669 extern int TotalRam;
2670 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2675 extern int Model_ram;
2676 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2680 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2682 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2684 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2688 extern int D3D_textures_in;
2689 extern int Glide_textures_in;
2690 extern int Glide_textures_in_frame;
2691 extern int Glide_explosion_vram;
2692 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2694 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2696 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2703 if ( Show_player_pos ) {
2707 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));
2710 MONITOR_INC(NumPolys, modelstats_num_polys);
2711 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2712 MONITOR_INC(NumVerts, modelstats_num_verts );
2714 modelstats_num_polys = 0;
2715 modelstats_num_polys_drawn = 0;
2716 modelstats_num_verts = 0;
2717 modelstats_num_sortnorms = 0;
2721 void game_show_standalone_framerate()
2723 float frame_rate=30.0f;
2724 if ( frame_int == -1 ) {
2726 for (i=0; i<FRAME_FILTER; i++ ) {
2727 frametimes[i] = 0.0f;
2732 frametotal -= frametimes[frame_int];
2733 frametotal += flFrametime;
2734 frametimes[frame_int] = flFrametime;
2735 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2737 if ( frametotal != 0.0 ) {
2738 if ( Framecount >= FRAME_FILTER ){
2739 frame_rate = FRAME_FILTER / frametotal;
2741 frame_rate = Framecount / frametotal;
2744 std_set_standalone_fps(frame_rate);
2748 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2749 void game_show_time_left()
2753 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2754 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2755 // checking how much time is left
2757 if ( Mission_end_time == -1 ){
2761 diff = f2i(Mission_end_time - Missiontime);
2762 // be sure to bash to 0. diff could be negative on frame that we quit mission
2767 hud_set_default_color();
2768 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2771 //========================================================================================
2772 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2773 //========================================================================================
2777 DCF(ai_pause,"Pauses ai")
2780 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2781 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2782 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2783 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2786 obj_init_all_ships_physics();
2789 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2790 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2793 DCF(single_step,"Single steps the game")
2796 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2797 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2798 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2799 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2801 last_single_step = 0; // Make so single step waits a frame before stepping
2804 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2805 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2808 DCF_BOOL(physics_pause, physics_paused)
2809 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2810 DCF_BOOL(ai_firing, Ai_firing_enabled )
2812 // Create some simple aliases to these commands...
2813 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2814 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2815 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2816 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2817 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2820 //========================================================================================
2821 //========================================================================================
2824 void game_training_pause_do()
2828 key = game_check_key();
2830 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2837 void game_increase_skill_level()
2840 if (Game_skill_level >= NUM_SKILL_LEVELS){
2841 Game_skill_level = 0;
2845 int Player_died_time;
2847 int View_percent = 100;
2850 DCF(view, "Sets the percent of the 3d view to render.")
2853 dc_get_arg(ARG_INT);
2854 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2855 View_percent = Dc_arg_int;
2857 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2863 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2867 dc_printf("View is set to %d%%\n", View_percent );
2872 // Set the clip region for the 3d rendering window
2873 void game_set_view_clip()
2875 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2876 // Set the clip region for the letterbox "dead view"
2877 int yborder = gr_screen.max_h/4;
2879 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2880 // J.S. I've changed my ways!! See the new "no constants" code!!!
2881 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2883 // Set the clip region for normal view
2884 if ( View_percent >= 100 ) {
2887 int xborder, yborder;
2889 if ( View_percent < 5 ) {
2893 float fp = i2fl(View_percent)/100.0f;
2894 int fi = fl2i(fl_sqrt(fp)*100.0f);
2895 if ( fi > 100 ) fi=100;
2897 xborder = ( gr_screen.max_w*(100-fi) )/200;
2898 yborder = ( gr_screen.max_h*(100-fi) )/200;
2900 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2906 void show_debug_stuff()
2909 int laser_count = 0, missile_count = 0;
2911 for (i=0; i<MAX_OBJECTS; i++) {
2912 if (Objects[i].type == OBJ_WEAPON){
2913 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2915 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2921 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2924 extern int Tool_enabled;
2929 int tst_bitmap = -1;
2931 float tst_offset, tst_offset_total;
2934 void game_tst_frame_pre()
2942 g3_rotate_vertex(&v, &tst_pos);
2943 g3_project_vertex(&v);
2946 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2950 // big ship? always tst
2952 // within 3000 meters
2953 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2957 // within 300 meters
2958 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2965 void game_tst_frame()
2975 tst_time = time(NULL);
2977 // load the tst bitmap
2978 switch((int)frand_range(0.0f, 3.0)){
2980 tst_bitmap = bm_load("ig_jim");
2982 mprintf(("TST 0\n"));
2986 tst_bitmap = bm_load("ig_kan");
2988 mprintf(("TST 1\n"));
2992 tst_bitmap = bm_load("ig_jim");
2994 mprintf(("TST 2\n"));
2998 tst_bitmap = bm_load("ig_kan");
3000 mprintf(("TST 3\n"));
3009 // get the tst bitmap dimensions
3011 bm_get_info(tst_bitmap, &w, &h);
3014 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3016 snd_play(&Snds[SND_VASUDAN_BUP]);
3018 // tst x and direction
3022 tst_offset_total = (float)w;
3023 tst_offset = (float)w;
3025 tst_x = (float)gr_screen.max_w;
3026 tst_offset_total = (float)-w;
3027 tst_offset = (float)w;
3035 float diff = (tst_offset_total / 0.5f) * flFrametime;
3041 tst_offset -= fl_abs(diff);
3042 } else if(tst_mode == 2){
3045 tst_offset -= fl_abs(diff);
3049 gr_set_bitmap(tst_bitmap);
3050 gr_bitmap((int)tst_x, (int)tst_y);
3053 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3057 // if we passed the switch point
3058 if(tst_offset <= 0.0f){
3063 tst_stamp = timestamp(1000);
3064 tst_offset = fl_abs(tst_offset_total);
3075 void game_tst_mark(object *objp, ship *shipp)
3084 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3087 sip = &Ship_info[shipp->ship_info_index];
3094 tst_pos = objp->pos;
3095 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3101 extern void render_shields();
3103 void player_repair_frame(float frametime)
3105 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3107 for(idx=0;idx<MAX_PLAYERS;idx++){
3110 np = &Net_players[idx];
3112 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)){
3114 // don't rearm/repair if the player is dead or dying/departing
3115 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3116 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3121 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3122 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3128 #define NUM_FRAMES_TEST 300
3129 #define NUM_MIXED_SOUNDS 16
3130 void do_timing_test(float flFrametime)
3132 static int framecount = 0;
3133 static int test_running = 0;
3134 static float test_time = 0.0f;
3136 static int snds[NUM_MIXED_SOUNDS];
3139 if ( test_running ) {
3141 test_time += flFrametime;
3142 if ( framecount >= NUM_FRAMES_TEST ) {
3144 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3145 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3150 if ( Test_begin == 1 ) {
3156 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3159 // start looping digital sounds
3160 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3161 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3168 DCF(dcf_fov, "Change the field of view")
3171 dc_get_arg(ARG_FLOAT|ARG_NONE);
3172 if ( Dc_arg_type & ARG_NONE ) {
3173 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3174 dc_printf( "Zoom factor reset\n" );
3176 if ( Dc_arg_type & ARG_FLOAT ) {
3177 if (Dc_arg_float < 0.25f) {
3178 Viewer_zoom = 0.25f;
3179 dc_printf("Zoom factor pinned at 0.25.\n");
3180 } else if (Dc_arg_float > 1.25f) {
3181 Viewer_zoom = 1.25f;
3182 dc_printf("Zoom factor pinned at 1.25.\n");
3184 Viewer_zoom = Dc_arg_float;
3190 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3193 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3197 DCF(framerate_cap, "Sets the framerate cap")
3200 dc_get_arg(ARG_INT);
3201 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3202 Framerate_cap = Dc_arg_int;
3204 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3210 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3211 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3212 dc_printf("[n] must be from 1 to 120.\n");
3216 if ( Framerate_cap )
3217 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3219 dc_printf("There is no framerate cap currently active.\n");
3223 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3224 int Show_viewing_from_self = 0;
3226 void say_view_target()
3228 object *view_target;
3230 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3231 view_target = &Objects[Player_ai->target_objnum];
3233 view_target = Player_obj;
3235 if (Game_mode & GM_DEAD) {
3236 if (Player_ai->target_objnum != -1)
3237 view_target = &Objects[Player_ai->target_objnum];
3240 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3241 if (view_target != Player_obj){
3243 char *view_target_name = NULL;
3244 switch(Objects[Player_ai->target_objnum].type) {
3246 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3249 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3250 Viewer_mode &= ~VM_OTHER_SHIP;
3252 case OBJ_JUMP_NODE: {
3253 char jump_node_name[128];
3254 strcpy(jump_node_name, XSTR( "jump node", 184));
3255 view_target_name = jump_node_name;
3256 Viewer_mode &= ~VM_OTHER_SHIP;
3265 if ( view_target_name ) {
3266 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3267 Show_viewing_from_self = 1;
3270 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3271 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3272 Show_viewing_from_self = 1;
3274 if (Show_viewing_from_self)
3275 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3280 Last_view_target = view_target;
3284 float Game_hit_x = 0.0f;
3285 float Game_hit_y = 0.0f;
3287 // Reset at the beginning of each frame
3288 void game_whack_reset()
3294 // Apply a 2d whack to the player
3295 void game_whack_apply( float x, float y )
3297 // Do some force feedback
3298 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3304 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3307 // call to apply a "shudder"
3308 void game_shudder_apply(int time, float intensity)
3310 Game_shudder_time = timestamp(time);
3311 Game_shudder_total = time;
3312 Game_shudder_intensity = intensity;
3315 #define FF_SCALE 10000
3316 void apply_hud_shake(matrix *eye_orient)
3318 if (Viewer_obj == Player_obj) {
3319 physics_info *pi = &Player_obj->phys_info;
3327 // Make eye shake due to afterburner
3328 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3331 dtime = timestamp_until(pi->afterburner_decay);
3335 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3336 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3339 // Make eye shake due to engine wash
3341 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3344 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3345 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3347 // get the intensity
3348 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3352 vm_vec_rand_vec_quick(&rand_vec);
3355 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3359 // make hud shake due to shuddering
3360 if(Game_shudder_time != -1){
3361 // if the timestamp has elapsed
3362 if(timestamp_elapsed(Game_shudder_time)){
3363 Game_shudder_time = -1;
3365 // otherwise apply some shudder
3369 dtime = timestamp_until(Game_shudder_time);
3373 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));
3374 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));
3379 vm_angles_2_matrix(&tm, &tangles);
3380 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3381 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3382 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3383 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3388 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3390 // Player's velocity just before he blew up. Used to keep camera target moving.
3391 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3393 // Set eye_pos and eye_orient based on view mode.
3394 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3398 static int last_Viewer_mode = 0;
3399 static int last_Game_mode = 0;
3400 static int last_Viewer_objnum = -1;
3402 // This code is supposed to detect camera "cuts"... like going between
3405 // determine if we need to regenerate the nebula
3406 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3407 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3408 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3409 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3410 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3411 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3412 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3413 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3414 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3417 // regenerate the nebula
3421 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3422 //mprintf(( "************** Camera cut! ************\n" ));
3423 last_Viewer_mode = Viewer_mode;
3424 last_Game_mode = Game_mode;
3426 // Camera moved. Tell stars & debris to not do blurring.
3432 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3433 player_display_packlock_view();
3436 game_set_view_clip();
3438 if (Game_mode & GM_DEAD) {
3439 vector vec_to_deader, view_pos;
3442 Viewer_mode |= VM_DEAD_VIEW;
3444 if (Player_ai->target_objnum != -1) {
3445 int view_from_player = 1;
3447 if (Viewer_mode & VM_OTHER_SHIP) {
3448 // View from target.
3449 Viewer_obj = &Objects[Player_ai->target_objnum];
3451 last_Viewer_objnum = Player_ai->target_objnum;
3453 if ( Viewer_obj->type == OBJ_SHIP ) {
3454 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3455 view_from_player = 0;
3458 last_Viewer_objnum = -1;
3461 if ( view_from_player ) {
3462 // View target from player ship.
3464 *eye_pos = Player_obj->pos;
3465 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3466 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3469 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3471 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3472 dist += flFrametime * 16.0f;
3474 vm_vec_scale(&vec_to_deader, -dist);
3475 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3477 view_pos = Player_obj->pos;
3479 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3480 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3481 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3482 Dead_player_last_vel = Player_obj->phys_info.vel;
3483 //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));
3484 } else if (Player_ai->target_objnum != -1) {
3485 view_pos = Objects[Player_ai->target_objnum].pos;
3487 // Make camera follow explosion, but gradually slow down.
3488 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3489 view_pos = Player_obj->pos;
3490 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3491 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3494 *eye_pos = Dead_camera_pos;
3496 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3498 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3503 // if supernova shockwave
3504 if(supernova_camera_cut()){
3508 // call it dead view
3509 Viewer_mode |= VM_DEAD_VIEW;
3511 // set eye pos and orient
3512 supernova_set_view(eye_pos, eye_orient);
3514 // If already blown up, these other modes can override.
3515 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3516 Viewer_mode &= ~VM_DEAD_VIEW;
3518 Viewer_obj = Player_obj;
3520 if (Viewer_mode & VM_OTHER_SHIP) {
3521 if (Player_ai->target_objnum != -1){
3522 Viewer_obj = &Objects[Player_ai->target_objnum];
3523 last_Viewer_objnum = Player_ai->target_objnum;
3525 Viewer_mode &= ~VM_OTHER_SHIP;
3526 last_Viewer_objnum = -1;
3529 last_Viewer_objnum = -1;
3532 if (Viewer_mode & VM_EXTERNAL) {
3535 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3536 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3538 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3540 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3541 vm_vec_normalize(&eye_dir);
3542 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3545 // Modify the orientation based on head orientation.
3546 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3548 } else if ( Viewer_mode & VM_CHASE ) {
3551 if ( Viewer_obj->phys_info.speed < 0.1 )
3552 move_dir = Viewer_obj->orient.v.fvec;
3554 move_dir = Viewer_obj->phys_info.vel;
3555 vm_vec_normalize(&move_dir);
3558 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3559 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3560 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3561 vm_vec_normalize(&eye_dir);
3563 // JAS: I added the following code because if you slew up using
3564 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3565 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3566 // call because the up and the forward vector are the same. I fixed
3567 // it by adding in a fraction of the right vector all the time to the
3569 vector tmp_up = Viewer_obj->orient.v.uvec;
3570 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3572 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3575 // Modify the orientation based on head orientation.
3576 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3577 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3578 *eye_pos = Camera_pos;
3580 ship * shipp = &Ships[Player_obj->instance];
3582 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3583 vm_vec_normalize(&eye_dir);
3584 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3587 // get an eye position based upon the correct type of object
3588 switch(Viewer_obj->type){
3590 // make a call to get the eye point for the player object
3591 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3594 // make a call to get the eye point for the player object
3595 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3601 #ifdef JOHNS_DEBUG_CODE
3602 john_debug_stuff(&eye_pos, &eye_orient);
3608 apply_hud_shake(eye_orient);
3610 // setup neb2 rendering
3611 neb2_render_setup(eye_pos, eye_orient);
3615 extern void ai_debug_render_stuff();
3618 int Game_subspace_effect = 0;
3619 DCF_BOOL( subspace, Game_subspace_effect );
3621 // Does everything needed to render a frame
3622 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3626 g3_start_frame(game_zbuffer);
3627 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3629 // maybe offset the HUD (jitter stuff)
3630 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3631 HUD_set_offsets(Viewer_obj, !dont_offset);
3633 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3634 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3635 // must be done before ships are rendered
3636 if ( MULTIPLAYER_CLIENT ) {
3637 shield_point_multi_setup();
3640 if ( Game_subspace_effect ) {
3641 stars_draw(0,0,0,1);
3643 stars_draw(1,1,1,0);
3646 obj_render_all(obj_render);
3647 beam_render_all(); // render all beam weapons
3648 particle_render_all(); // render particles after everything else.
3649 trail_render_all(); // render missilie trails after everything else.
3650 mflash_render_all(); // render all muzzle flashes
3652 // Why do we not show the shield effect in these modes? Seems ok.
3653 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3657 // render nebula lightning
3660 // render local player nebula
3661 neb2_render_player();
3664 ai_debug_render_stuff();
3667 #ifndef RELEASE_REAL
3668 // game_framerate_check();
3672 extern void snd_spew_debug_info();
3673 snd_spew_debug_info();
3676 //================ END OF 3D RENDERING STUFF ====================
3680 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3681 hud_maybe_clear_head_area();
3682 anim_render_all(0, flFrametime);
3685 extern int Multi_display_netinfo;
3686 if(Multi_display_netinfo){
3687 extern void multi_display_netinfo();
3688 multi_display_netinfo();
3691 game_tst_frame_pre();
3694 do_timing_test(flFrametime);
3698 extern int OO_update_index;
3699 multi_rate_display(OO_update_index, 375, 0);
3704 extern void oo_display();
3711 //#define JOHNS_DEBUG_CODE 1
3713 #ifdef JOHNS_DEBUG_CODE
3714 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3716 //if ( keyd_pressed[KEY_LSHIFT] )
3718 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3720 model_subsystem *turret = tsys->system_info;
3722 if (turret->type == SUBSYSTEM_TURRET ) {
3723 vector v.fvec, v.uvec;
3724 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3726 ship_model_start(tobj);
3728 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3729 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3730 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3732 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3734 ship_model_stop(tobj);
3744 // following function for dumping frames for purposes of building trailers.
3747 // function to toggle state of dumping every frame into PCX when playing the game
3748 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3752 if ( Debug_dump_frames == 0 ) {
3754 Debug_dump_frames = 15;
3755 Debug_dump_trigger = 0;
3756 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3757 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3760 Debug_dump_frames = 0;
3761 Debug_dump_trigger = 0;
3762 gr_dump_frame_stop();
3763 dc_printf( "Frame dumping is now OFF\n" );
3769 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3773 if ( Debug_dump_frames == 0 ) {
3775 Debug_dump_frames = 15;
3776 Debug_dump_trigger = 1;
3777 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3778 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3781 Debug_dump_frames = 0;
3782 Debug_dump_trigger = 0;
3783 gr_dump_frame_stop();
3784 dc_printf( "Frame dumping is now OFF\n" );
3790 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3794 if ( Debug_dump_frames == 0 ) {
3796 Debug_dump_frames = 30;
3797 Debug_dump_trigger = 0;
3798 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3799 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3802 Debug_dump_frames = 0;
3803 Debug_dump_trigger = 0;
3804 gr_dump_frame_stop();
3805 dc_printf( "Frame dumping is now OFF\n" );
3811 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3815 if ( Debug_dump_frames == 0 ) {
3817 Debug_dump_frames = 30;
3818 Debug_dump_trigger = 1;
3819 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3820 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3823 Debug_dump_frames = 0;
3824 Debug_dump_trigger = 0;
3825 gr_dump_frame_stop();
3826 dc_printf( "Triggered frame dumping is now OFF\n" );
3832 void game_maybe_dump_frame()
3834 if ( !Debug_dump_frames ){
3838 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3845 Debug_dump_frame_num++;
3851 extern int Player_dead_state;
3853 // Flip the page and time how long it took.
3854 void game_flip_page_and_time_it()
3859 t1 = timer_get_fixed_seconds();
3861 t2 = timer_get_fixed_seconds();
3864 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3865 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3872 void game_simulation_frame()
3874 // blow ships up in multiplayer dogfight
3875 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){
3876 // blow up all non-player ships
3877 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3880 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3882 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)){
3883 moveup = GET_NEXT(moveup);
3886 shipp = &Ships[Objects[moveup->objnum].instance];
3887 sip = &Ship_info[shipp->ship_info_index];
3889 // only blow up small ships
3890 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3891 // function to simply explode a ship where it is currently at
3892 ship_self_destruct( &Objects[moveup->objnum] );
3895 moveup = GET_NEXT(moveup);
3901 // process AWACS stuff - do this first thing
3904 // single player, set Player hits_this_frame to 0
3905 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3906 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3907 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3911 supernova_process();
3912 if(supernova_active() >= 5){
3916 // fire targeting lasers now so that
3917 // 1 - created this frame
3918 // 2 - collide this frame
3919 // 3 - render this frame
3920 // 4 - ignored and deleted next frame
3921 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3923 ship_process_targeting_lasers();
3925 // do this here so that it works for multiplayer
3927 // get viewer direction
3928 int viewer_direction = PHYSICS_VIEWER_REAR;
3930 if(Viewer_mode == 0){
3931 viewer_direction = PHYSICS_VIEWER_FRONT;
3933 if(Viewer_mode & VM_PADLOCK_UP){
3934 viewer_direction = PHYSICS_VIEWER_UP;
3936 else if(Viewer_mode & VM_PADLOCK_REAR){
3937 viewer_direction = PHYSICS_VIEWER_REAR;
3939 else if(Viewer_mode & VM_PADLOCK_LEFT){
3940 viewer_direction = PHYSICS_VIEWER_LEFT;
3942 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3943 viewer_direction = PHYSICS_VIEWER_RIGHT;
3946 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3948 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3951 #define VM_PADLOCK_UP (1 << 7)
3952 #define VM_PADLOCK_REAR (1 << 8)
3953 #define VM_PADLOCK_LEFT (1 << 9)
3954 #define VM_PADLOCK_RIGHT (1 << 10)
3956 // evaluate mission departures and arrivals before we process all objects.
3957 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3959 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3960 // ships/wing packets.
3961 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3962 mission_parse_eval_stuff();
3965 // if we're an observer, move ourselves seperately from the standard physics
3966 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3967 obj_observer_move(flFrametime);
3970 // move all the objects now
3971 obj_move_all(flFrametime);
3973 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3974 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3975 // ship_check_cargo_all();
3976 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3977 mission_eval_goals();
3981 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3982 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3983 training_check_objectives();
3986 // do all interpolation now
3987 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3988 // client side processing of warping in effect stages
3989 multi_do_client_warp(flFrametime);
3991 // client side movement of an observer
3992 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3993 obj_observer_move(flFrametime);
3996 // move all objects - does interpolation now as well
3997 obj_move_all(flFrametime);
4000 // only process the message queue when the player is "in" the game
4001 if ( !Pre_player_entry ){
4002 message_queue_process(); // process any messages send to the player
4005 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4006 message_maybe_distort(); // maybe distort incoming message if comms damaged
4007 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
4008 player_process_pending_praise(); // maybe send off a delayed praise message to the player
4009 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4012 if(!(Game_mode & GM_STANDALONE_SERVER)){
4013 // process some stuff every frame (before frame is rendered)
4014 emp_process_local();
4016 hud_update_frame(); // update hud systems
4018 if (!physics_paused) {
4019 // Move particle system
4020 particle_move_all(flFrametime);
4022 // Move missile trails
4023 trail_move_all(flFrametime);
4025 // process muzzle flashes
4026 mflash_process_all();
4028 // Flash the gun flashes
4029 shipfx_flash_do_frame(flFrametime);
4031 shockwave_move_all(flFrametime); // update all the shockwaves
4034 // subspace missile strikes
4037 obj_snd_do_frame(); // update the object-linked persistant sounds
4038 game_maybe_update_sound_environment();
4039 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4041 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4043 if ( Game_subspace_effect ) {
4044 game_start_subspace_ambient_sound();
4050 // Maybe render and process the dead-popup
4051 void game_maybe_do_dead_popup(float frametime)
4053 if ( popupdead_is_active() ) {
4055 int choice = popupdead_do_frame(frametime);
4057 if ( Game_mode & GM_NORMAL ) {
4061 if(game_do_cd_mission_check(Game_current_mission_filename)){
4062 gameseq_post_event(GS_EVENT_ENTER_GAME);
4064 gameseq_post_event(GS_EVENT_MAIN_MENU);
4069 gameseq_post_event(GS_EVENT_END_GAME);
4074 if(game_do_cd_mission_check(Game_current_mission_filename)){
4075 gameseq_post_event(GS_EVENT_START_GAME);
4077 gameseq_post_event(GS_EVENT_MAIN_MENU);
4081 // this should only happen during a red alert mission
4084 Assert(The_mission.red_alert);
4085 if(!The_mission.red_alert){
4087 if(game_do_cd_mission_check(Game_current_mission_filename)){
4088 gameseq_post_event(GS_EVENT_START_GAME);
4090 gameseq_post_event(GS_EVENT_MAIN_MENU);
4095 // choose the previous mission
4096 mission_campaign_previous_mission();
4098 if(game_do_cd_mission_check(Game_current_mission_filename)){
4099 gameseq_post_event(GS_EVENT_START_GAME);
4101 gameseq_post_event(GS_EVENT_MAIN_MENU);
4112 case POPUPDEAD_DO_MAIN_HALL:
4113 multi_quit_game(PROMPT_NONE,-1);
4116 case POPUPDEAD_DO_RESPAWN:
4117 multi_respawn_normal();
4118 event_music_player_respawn();
4121 case POPUPDEAD_DO_OBSERVER:
4122 multi_respawn_observer();
4123 event_music_player_respawn_as_observer();
4132 if ( leave_popup ) {
4138 // returns true if player is actually in a game_play stats
4139 int game_actually_playing()
4143 state = gameseq_get_state();
4144 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4150 // Draw the 2D HUD gauges
4151 void game_render_hud_2d()
4153 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4157 HUD_render_2d(flFrametime);
4161 // Draw the 3D-dependant HUD gauges
4162 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4164 g3_start_frame(0); // 0 = turn zbuffering off
4165 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4167 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4168 HUD_render_3d(flFrametime);
4172 game_sunspot_process(flFrametime);
4174 // Diminish the palette effect
4175 game_flash_diminish(flFrametime);
4183 int actually_playing;
4184 fix total_time1, total_time2;
4185 fix render2_time1=0, render2_time2=0;
4186 fix render3_time1=0, render3_time2=0;
4187 fix flip_time1=0, flip_time2=0;
4188 fix clear_time1=0, clear_time2=0;
4194 if (Framerate_delay) {
4195 int start_time = timer_get_milliseconds();
4196 while (timer_get_milliseconds() < start_time + Framerate_delay)
4202 demo_do_frame_start();
4204 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4209 // start timing frame
4210 timing_frame_start();
4212 total_time1 = timer_get_fixed_seconds();
4214 // var to hold which state we are in
4215 actually_playing = game_actually_playing();
4217 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4218 if (!(Game_mode & GM_STANDALONE_SERVER)){
4219 Assert( OBJ_INDEX(Player_obj) >= 0 );
4223 if (Missiontime > Entry_delay_time){
4224 Pre_player_entry = 0;
4226 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4229 // Note: These are done even before the player enters, else buffers can overflow.
4230 if (! (Game_mode & GM_STANDALONE_SERVER)){
4234 shield_frame_init();
4236 if ( Player->control_mode != PCM_NORMAL )
4239 if ( !Pre_player_entry && actually_playing ) {
4240 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4242 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4243 game_process_keys();
4245 // don't read flying controls if we're playing a demo back
4246 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4247 read_player_controls( Player_obj, flFrametime);
4251 // if we're not the master, we may have to send the server-critical ship status button_info bits
4252 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4253 multi_maybe_send_ship_status();
4258 // Reset the whack stuff
4261 // These two lines must be outside of Pre_player_entry code,
4262 // otherwise too many lights are added.
4265 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4269 game_simulation_frame();
4271 // if not actually in a game play state, then return. This condition could only be true in
4272 // a multiplayer game.
4273 if ( !actually_playing ) {
4274 Assert( Game_mode & GM_MULTIPLAYER );
4278 if (!Pre_player_entry) {
4279 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4280 clear_time1 = timer_get_fixed_seconds();
4281 // clear the screen to black
4283 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4287 clear_time2 = timer_get_fixed_seconds();
4288 render3_time1 = timer_get_fixed_seconds();
4289 game_render_frame_setup(&eye_pos, &eye_orient);
4290 game_render_frame( &eye_pos, &eye_orient );
4292 // save the eye position and orientation
4293 if ( Game_mode & GM_MULTIPLAYER ) {
4294 Net_player->s_info.eye_pos = eye_pos;
4295 Net_player->s_info.eye_orient = eye_orient;
4298 hud_show_target_model();
4300 // check to see if we should display the death died popup
4301 if(Game_mode & GM_DEAD_BLEW_UP){
4302 if(Game_mode & GM_MULTIPLAYER){
4303 // catch the situation where we're supposed to be warping out on this transition
4304 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4305 gameseq_post_event(GS_EVENT_DEBRIEF);
4306 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4307 Player_died_popup_wait = -1;
4311 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4312 Player_died_popup_wait = -1;
4318 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4319 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4320 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4321 if(!popupdead_is_active()){
4325 Player_multi_died_check = -1;
4329 render3_time2 = timer_get_fixed_seconds();
4330 render2_time1 = timer_get_fixed_seconds();
4333 game_get_framerate();
4334 game_show_framerate();
4336 game_show_time_left();
4338 // Draw the 2D HUD gauges
4339 if(supernova_active() < 3){
4340 game_render_hud_2d();
4343 game_set_view_clip();
4345 // Draw 3D HUD gauges
4346 game_render_hud_3d(&eye_pos, &eye_orient);
4350 render2_time2 = timer_get_fixed_seconds();
4352 // maybe render and process the dead popup
4353 game_maybe_do_dead_popup(flFrametime);
4355 // start timing frame
4356 timing_frame_stop();
4357 // timing_display(30, 10);
4359 // If a regular popup is active, don't flip (popup code flips)
4360 if( !popup_running_state() ){
4361 flip_time1 = timer_get_fixed_seconds();
4362 game_flip_page_and_time_it();
4363 flip_time2 = timer_get_fixed_seconds();
4367 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4370 game_show_standalone_framerate();
4374 game_do_training_checks();
4377 // process lightning (nebula only)
4380 total_time2 = timer_get_fixed_seconds();
4382 // Got some timing numbers
4383 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4384 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4385 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4386 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4387 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4390 demo_do_frame_end();
4392 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4398 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4399 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4400 // died. This resulted in screwed up death sequences.
4402 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4403 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4404 static int timer_paused=0;
4405 #if defined(TIMER_TEST) && !defined(NDEBUG)
4406 static int stop_count,start_count;
4407 static int time_stopped,time_started;
4409 int saved_timestamp_ticker = -1;
4411 void game_reset_time()
4413 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4417 // Last_time = timer_get_fixed_seconds();
4423 void game_stop_time()
4425 if (timer_paused==0) {
4427 time = timer_get_fixed_seconds();
4428 // Save how much time progressed so far in the frame so we can
4429 // use it when we unpause.
4430 Last_delta_time = time - Last_time;
4432 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4433 if (Last_delta_time < 0) {
4434 #if defined(TIMER_TEST) && !defined(NDEBUG)
4435 Int3(); //get Matt!!!!
4437 Last_delta_time = 0;
4439 #if defined(TIMER_TEST) && !defined(NDEBUG)
4440 time_stopped = time;
4443 // Stop the timer_tick stuff...
4444 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4445 saved_timestamp_ticker = timestamp_ticker;
4449 #if defined(TIMER_TEST) && !defined(NDEBUG)
4454 void game_start_time()
4457 Assert(timer_paused >= 0);
4458 if (timer_paused==0) {
4460 time = timer_get_fixed_seconds();
4461 #if defined(TIMER_TEST) && !defined(NDEBUG)
4463 Int3(); //get Matt!!!!
4466 // Take current time, and set it backwards to account for time
4467 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4468 // will be correct when it goes to calculate the frametime next
4470 Last_time = time - Last_delta_time;
4471 #if defined(TIMER_TEST) && !defined(NDEBUG)
4472 time_started = time;
4475 // Restore the timer_tick stuff...
4476 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4477 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4478 timestamp_ticker = saved_timestamp_ticker;
4479 saved_timestamp_ticker = -1;
4482 #if defined(TIMER_TEST) && !defined(NDEBUG)
4488 void game_set_frametime(int state)
4491 float frame_cap_diff;
4493 thistime = timer_get_fixed_seconds();
4495 if ( Last_time == 0 )
4496 Frametime = F1_0 / 30;
4498 Frametime = thistime - Last_time;
4500 // Frametime = F1_0 / 30;
4502 fix debug_frametime = Frametime; // Just used to display frametime.
4504 // If player hasn't entered mission yet, make frame take 1/4 second.
4505 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4508 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4510 fix frame_speed = F1_0 / Debug_dump_frames;
4512 if (Frametime > frame_speed ){
4513 nprintf(("warning","slow frame: %x\n",Frametime));
4516 thistime = timer_get_fixed_seconds();
4517 Frametime = thistime - Last_time;
4518 } while (Frametime < frame_speed );
4520 Frametime = frame_speed;
4524 Assert( Framerate_cap > 0 );
4526 // Cap the framerate so it doesn't get too high.
4530 cap = F1_0/Framerate_cap;
4531 if (Frametime < cap) {
4532 thistime = cap - Frametime;
4533 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4534 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4536 thistime = timer_get_fixed_seconds();
4540 if((Game_mode & GM_STANDALONE_SERVER) &&
4541 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4543 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4544 Sleep((DWORD)(frame_cap_diff*1000));
4546 thistime += fl2f((frame_cap_diff));
4548 Frametime = thistime - Last_time;
4551 // If framerate is too low, cap it.
4552 if (Frametime > MAX_FRAMETIME) {
4554 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4556 // to remove warnings in release build
4557 debug_frametime = fl2f(flFrametime);
4559 Frametime = MAX_FRAMETIME;
4562 Frametime = fixmul(Frametime, Game_time_compression);
4564 Last_time = thistime;
4565 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4567 flFrametime = f2fl(Frametime);
4568 //if(!(Game_mode & GM_PLAYING_DEMO)){
4569 timestamp_inc(flFrametime);
4571 /* if ((Framecount > 0) && (Framecount < 10)) {
4572 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4577 // This is called from game_do_frame(), and from navmap_do_frame()
4578 void game_update_missiontime()
4580 // TODO JAS: Put in if and move this into game_set_frametime,
4581 // fix navmap to call game_stop/start_time
4582 //if ( !timer_paused )
4583 Missiontime += Frametime;
4586 void game_do_frame()
4588 game_set_frametime(GS_STATE_GAME_PLAY);
4589 game_update_missiontime();
4591 if (Game_mode & GM_STANDALONE_SERVER) {
4592 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4595 if ( game_single_step && (last_single_step == game_single_step) ) {
4596 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4597 while( key_checkch() == 0 )
4599 os_set_title( XSTR( "FreeSpace", 171) );
4600 Last_time = timer_get_fixed_seconds();
4603 last_single_step = game_single_step;
4605 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4606 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4610 Keep_mouse_centered = 0;
4611 monitor_update(); // Update monitor variables
4614 void multi_maybe_do_frame()
4616 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4621 int Joymouse_button_status = 0;
4623 // Flush all input devices
4631 Joymouse_button_status = 0;
4633 //mprintf(("Game flush!\n" ));
4636 // function for multiplayer only which calls game_do_state_common() when running the
4638 void game_do_dc_networking()
4640 Assert( Game_mode & GM_MULTIPLAYER );
4642 game_do_state_common( gameseq_get_state() );
4645 // Call this whenever in a loop, or when you need to check for a keystroke.
4646 int game_check_key()
4652 // convert keypad enter to normal enter
4653 if ((k & KEY_MASK) == KEY_PADENTER)
4654 k = (k & ~KEY_MASK) | KEY_ENTER;
4661 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4662 static int Demo_show_trailer_timestamp = 0;
4664 void demo_reset_trailer_timer()
4666 Demo_show_trailer_timestamp = timer_get_milliseconds();
4669 void demo_maybe_show_trailer(int k)
4672 // if key pressed, reset demo trailer timer
4674 demo_reset_trailer_timer();
4678 // if mouse moved, reset demo trailer timer
4681 mouse_get_delta(&dx, &dy);
4682 if ( (dx > 0) || (dy > 0) ) {
4683 demo_reset_trailer_timer();
4687 // if joystick has moved, reset demo trailer timer
4690 joy_get_delta(&dx, &dy);
4691 if ( (dx > 0) || (dy > 0) ) {
4692 demo_reset_trailer_timer();
4696 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4697 // the low-level code. Ugly, I know... but was the simplest and most
4700 // if 30 seconds since last demo trailer time reset, launch movie
4701 if ( os_foreground() ) {
4702 int now = timer_get_milliseconds();
4703 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4704 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4706 movie_play( NOX("fstrailer2.mve") );
4707 demo_reset_trailer_timer();
4715 // same as game_check_key(), except this is used while actually in the game. Since there
4716 // generally are differences between game control keys and general UI keys, makes sense to
4717 // have seperate functions for each case. If you are not checking a game control while in a
4718 // mission, you should probably be using game_check_key() instead.
4723 if (!os_foreground()) {
4728 // If we're in a single player game, pause it.
4729 if (!(Game_mode & GM_MULTIPLAYER)){
4730 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4731 game_process_pause_key();
4739 demo_maybe_show_trailer(k);
4742 // Move the mouse cursor with the joystick.
4743 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4744 // Move the mouse cursor with the joystick
4748 joy_get_pos( &jx, &jy, &jz, &jr );
4750 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4751 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4754 mouse_get_real_pos( &mx, &my );
4755 mouse_set_pos( mx+dx, my+dy );
4760 m = mouse_down(MOUSE_LEFT_BUTTON);
4762 if ( j != Joymouse_button_status ) {
4763 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4764 Joymouse_button_status = j;
4766 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4767 } else if ( (!j) && (m) ) {
4768 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4773 // if we should be ignoring keys because of some multiplayer situations
4774 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4778 // If a popup is running, don't process all the Fn keys
4779 if( popup_active() ) {
4783 state = gameseq_get_state();
4785 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4788 case KEY_DEBUGGED + KEY_BACKSP:
4793 launch_context_help();
4798 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4800 // don't allow f2 while warping out in multiplayer
4801 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4806 case GS_STATE_INITIAL_PLAYER_SELECT:
4807 case GS_STATE_OPTIONS_MENU:
4808 case GS_STATE_HUD_CONFIG:
4809 case GS_STATE_CONTROL_CONFIG:
4810 case GS_STATE_DEATH_DIED:
4811 case GS_STATE_DEATH_BLEW_UP:
4812 case GS_STATE_VIEW_MEDALS:
4816 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4823 // hotkey selection screen -- only valid from briefing and beyond.
4826 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) ) {
4827 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4833 case KEY_DEBUGGED + KEY_F3:
4834 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4837 case KEY_DEBUGGED + KEY_F4:
4838 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4842 if(Game_mode & GM_MULTIPLAYER){
4843 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4844 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4848 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4849 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4855 case KEY_ESC | KEY_SHIFTED:
4856 // make sure to quit properly out of multiplayer
4857 if(Game_mode & GM_MULTIPLAYER){
4858 multi_quit_game(PROMPT_NONE);
4861 gameseq_post_event( GS_EVENT_QUIT_GAME );
4866 case KEY_DEBUGGED + KEY_P:
4869 case KEY_PRINT_SCRN:
4871 static int counter = 0;
4876 sprintf( tmp_name, NOX("screen%02d"), counter );
4878 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4879 gr_print_screen(tmp_name);
4887 case KEY_SHIFTED | KEY_ENTER: {
4889 #if !defined(NDEBUG)
4891 if ( Game_mode & GM_NORMAL ){
4895 // if we're in multiplayer mode, do some special networking
4896 if(Game_mode & GM_MULTIPLAYER){
4897 debug_console(game_do_dc_networking);
4904 if ( Game_mode & GM_NORMAL )
4918 gameseq_post_event(GS_EVENT_QUIT_GAME);
4921 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4924 void camera_set_position( vector *pos )
4929 void camera_set_orient( matrix *orient )
4931 Camera_orient = *orient;
4934 void camera_set_velocity( vector *vel, int instantaneous )
4936 Camera_desired_velocity.xyz.x = 0.0f;
4937 Camera_desired_velocity.xyz.y = 0.0f;
4938 Camera_desired_velocity.xyz.z = 0.0f;
4940 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4941 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4942 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4944 if ( instantaneous ) {
4945 Camera_velocity = Camera_desired_velocity;
4953 vector new_vel, delta_pos;
4955 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4956 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4957 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4959 Camera_velocity = new_vel;
4961 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4963 vm_vec_add2( &Camera_pos, &delta_pos );
4965 float ot = Camera_time+0.0f;
4967 Camera_time += flFrametime;
4969 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4972 tmp.xyz.z = 4.739f; // always go this fast forward.
4974 // pick x and y velocities so they are always on a
4975 // circle with a 25 m radius.
4977 float tmp_angle = frand()*PI2;
4979 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4980 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4982 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4984 //mprintf(( "Changing velocity!\n" ));
4985 camera_set_velocity( &tmp, 0 );
4988 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4989 vector tmp = { 0.0f, 0.0f, 0.0f };
4990 camera_set_velocity( &tmp, 0 );
4995 void end_demo_campaign_do()
4997 #if defined(FS2_DEMO)
4998 // show upsell screens
4999 demo_upsell_show_screens();
5000 #elif defined(OEM_BUILD)
5001 // show oem upsell screens
5002 oem_upsell_show_screens();
5005 // drop into main hall
5006 gameseq_post_event( GS_EVENT_MAIN_MENU );
5009 // All code to process events. This is the only place
5010 // that you should change the state of the game.
5011 void game_process_event( int current_state, int event )
5013 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5016 case GS_EVENT_SIMULATOR_ROOM:
5017 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5020 case GS_EVENT_MAIN_MENU:
5021 gameseq_set_state(GS_STATE_MAIN_MENU);
5024 case GS_EVENT_OPTIONS_MENU:
5025 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5028 case GS_EVENT_BARRACKS_MENU:
5029 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5032 case GS_EVENT_TECH_MENU:
5033 gameseq_set_state(GS_STATE_TECH_MENU);
5036 case GS_EVENT_TRAINING_MENU:
5037 gameseq_set_state(GS_STATE_TRAINING_MENU);
5040 case GS_EVENT_START_GAME:
5041 Select_default_ship = 0;
5042 Player_multi_died_check = -1;
5043 gameseq_set_state(GS_STATE_CMD_BRIEF);
5046 case GS_EVENT_START_BRIEFING:
5047 gameseq_set_state(GS_STATE_BRIEFING);
5050 case GS_EVENT_DEBRIEF:
5051 // did we end the campaign in the main freespace 2 single player campaign?
5052 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5053 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5055 gameseq_set_state(GS_STATE_DEBRIEF);
5058 Player_multi_died_check = -1;
5061 case GS_EVENT_SHIP_SELECTION:
5062 gameseq_set_state( GS_STATE_SHIP_SELECT );
5065 case GS_EVENT_WEAPON_SELECTION:
5066 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5069 case GS_EVENT_ENTER_GAME:
5071 // maybe start recording a demo
5073 demo_start_record("test.fsd");
5077 if (Game_mode & GM_MULTIPLAYER) {
5078 // if we're respawning, make sure we change the view mode so that the hud shows up
5079 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5083 gameseq_set_state(GS_STATE_GAME_PLAY);
5085 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5088 Player_multi_died_check = -1;
5090 // clear multiplayer button info
5091 extern button_info Multi_ship_status_bi;
5092 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5094 Start_time = f2fl(timer_get_approx_seconds());
5096 mprintf(("Entering game at time = %7.3f\n", Start_time));
5100 case GS_EVENT_START_GAME_QUICK:
5101 Select_default_ship = 1;
5102 gameseq_post_event(GS_EVENT_ENTER_GAME);
5106 case GS_EVENT_END_GAME:
5107 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5108 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5109 gameseq_set_state(GS_STATE_MAIN_MENU);
5114 Player_multi_died_check = -1;
5117 case GS_EVENT_QUIT_GAME:
5118 main_hall_stop_music();
5119 main_hall_stop_ambient();
5120 gameseq_set_state(GS_STATE_QUIT_GAME);
5122 Player_multi_died_check = -1;
5125 case GS_EVENT_GAMEPLAY_HELP:
5126 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5129 case GS_EVENT_PAUSE_GAME:
5130 gameseq_push_state(GS_STATE_GAME_PAUSED);
5133 case GS_EVENT_DEBUG_PAUSE_GAME:
5134 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5137 case GS_EVENT_TRAINING_PAUSE:
5138 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5141 case GS_EVENT_PREVIOUS_STATE:
5142 gameseq_pop_state();
5145 case GS_EVENT_TOGGLE_FULLSCREEN:
5146 #ifndef HARDWARE_ONLY
5148 if ( gr_screen.mode == GR_SOFTWARE ) {
5149 gr_init( GR_640, GR_DIRECTDRAW );
5150 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5151 gr_init( GR_640, GR_SOFTWARE );
5157 case GS_EVENT_TOGGLE_GLIDE:
5159 if ( gr_screen.mode != GR_GLIDE ) {
5160 gr_init( GR_640, GR_GLIDE );
5162 gr_init( GR_640, GR_SOFTWARE );
5167 case GS_EVENT_LOAD_MISSION_MENU:
5168 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5171 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5172 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5175 case GS_EVENT_HUD_CONFIG:
5176 gameseq_push_state( GS_STATE_HUD_CONFIG );
5179 case GS_EVENT_CONTROL_CONFIG:
5180 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5183 case GS_EVENT_DEATH_DIED:
5184 gameseq_set_state( GS_STATE_DEATH_DIED );
5187 case GS_EVENT_DEATH_BLEW_UP:
5188 if ( current_state == GS_STATE_DEATH_DIED ) {
5189 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5190 event_music_player_death();
5192 // multiplayer clients set their extra check here
5193 if(Game_mode & GM_MULTIPLAYER){
5194 // set the multi died absolute last chance check
5195 Player_multi_died_check = time(NULL);
5198 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5202 case GS_EVENT_NEW_CAMPAIGN:
5203 if (!mission_load_up_campaign()){
5204 readyroom_continue_campaign();
5207 Player_multi_died_check = -1;
5210 case GS_EVENT_CAMPAIGN_CHEAT:
5211 if (!mission_load_up_campaign()){
5213 // bash campaign value
5214 extern char Main_hall_campaign_cheat[512];
5217 // look for the mission
5218 for(idx=0; idx<Campaign.num_missions; idx++){
5219 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5220 Campaign.next_mission = idx;
5221 Campaign.prev_mission = idx - 1;
5228 readyroom_continue_campaign();
5231 Player_multi_died_check = -1;
5234 case GS_EVENT_CAMPAIGN_ROOM:
5235 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5238 case GS_EVENT_CMD_BRIEF:
5239 gameseq_set_state(GS_STATE_CMD_BRIEF);
5242 case GS_EVENT_RED_ALERT:
5243 gameseq_set_state(GS_STATE_RED_ALERT);
5246 case GS_EVENT_CREDITS:
5247 gameseq_set_state( GS_STATE_CREDITS );
5250 case GS_EVENT_VIEW_MEDALS:
5251 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5254 case GS_EVENT_SHOW_GOALS:
5255 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5258 case GS_EVENT_HOTKEY_SCREEN:
5259 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5262 // multiplayer stuff follow these comments
5264 case GS_EVENT_MULTI_JOIN_GAME:
5265 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5268 case GS_EVENT_MULTI_HOST_SETUP:
5269 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5272 case GS_EVENT_MULTI_CLIENT_SETUP:
5273 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5276 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5277 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5280 case GS_EVENT_MULTI_STD_WAIT:
5281 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5284 case GS_EVENT_STANDALONE_MAIN:
5285 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5288 case GS_EVENT_MULTI_PAUSE:
5289 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5292 case GS_EVENT_INGAME_PRE_JOIN:
5293 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5296 case GS_EVENT_EVENT_DEBUG:
5297 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5300 // Start a warpout where player automatically goes 70 no matter what
5301 // and can't cancel out of it.
5302 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5303 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5305 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5306 Player->saved_viewer_mode = Viewer_mode;
5307 Player->control_mode = PCM_WARPOUT_STAGE1;
5308 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5309 Warpout_time = 0.0f; // Start timer!
5312 case GS_EVENT_PLAYER_WARPOUT_START:
5313 if ( Player->control_mode != PCM_NORMAL ) {
5314 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5316 Player->saved_viewer_mode = Viewer_mode;
5317 Player->control_mode = PCM_WARPOUT_STAGE1;
5318 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5319 Warpout_time = 0.0f; // Start timer!
5320 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5324 case GS_EVENT_PLAYER_WARPOUT_STOP:
5325 if ( Player->control_mode != PCM_NORMAL ) {
5326 if ( !Warpout_forced ) { // cannot cancel forced warpout
5327 Player->control_mode = PCM_NORMAL;
5328 Viewer_mode = Player->saved_viewer_mode;
5329 hud_subspace_notify_abort();
5330 mprintf(( "Player put back to normal mode.\n" ));
5331 if ( Warpout_sound > -1 ) {
5332 snd_stop( Warpout_sound );
5339 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5340 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5341 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5342 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5344 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5345 shipfx_warpout_start( Player_obj );
5346 Player->control_mode = PCM_WARPOUT_STAGE2;
5347 Player->saved_viewer_mode = Viewer_mode;
5348 Viewer_mode |= VM_WARP_CHASE;
5350 vector tmp = Player_obj->pos;
5352 ship_get_eye( &tmp, &tmp_m, Player_obj );
5353 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5354 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5355 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5357 camera_set_position( &tmp );
5358 camera_set_orient( &Player_obj->orient );
5359 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5361 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5362 camera_set_velocity( &tmp_vel, 1);
5366 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5367 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5368 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5369 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5371 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5372 Player->control_mode = PCM_WARPOUT_STAGE3;
5376 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5377 mprintf(( "Player warped out. Going to debriefing!\n" ));
5378 Player->control_mode = PCM_NORMAL;
5379 Viewer_mode = Player->saved_viewer_mode;
5382 // we have a special debriefing screen for multiplayer furballs
5383 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5384 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5386 // do the normal debriefing for all other situations
5388 gameseq_post_event(GS_EVENT_DEBRIEF);
5392 case GS_EVENT_STANDALONE_POSTGAME:
5393 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5396 case GS_EVENT_INITIAL_PLAYER_SELECT:
5397 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5400 case GS_EVENT_GAME_INIT:
5401 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5402 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5404 // see if the command line option has been set to use the last pilot, and act acoordingly
5405 if( player_select_get_last_pilot() ) {
5406 // always enter the main menu -- do the automatic network startup stuff elsewhere
5407 // so that we still have valid checks for networking modes, etc.
5408 gameseq_set_state(GS_STATE_MAIN_MENU);
5410 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5415 case GS_EVENT_MULTI_MISSION_SYNC:
5416 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5419 case GS_EVENT_MULTI_START_GAME:
5420 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5423 case GS_EVENT_MULTI_HOST_OPTIONS:
5424 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5427 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5428 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5431 case GS_EVENT_TEAM_SELECT:
5432 gameseq_set_state(GS_STATE_TEAM_SELECT);
5435 case GS_EVENT_END_CAMPAIGN:
5436 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5439 case GS_EVENT_END_DEMO:
5440 gameseq_set_state(GS_STATE_END_DEMO);
5443 case GS_EVENT_LOOP_BRIEF:
5444 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5453 // Called when a state is being left.
5454 // The current state is still at old_state, but as soon as
5455 // this function leaves, then the current state will become
5456 // new state. You should never try to change the state
5457 // in here... if you think you need to, you probably really
5458 // need to post an event, not change the state.
5459 void game_leave_state( int old_state, int new_state )
5461 int end_mission = 1;
5463 switch (new_state) {
5464 case GS_STATE_GAME_PAUSED:
5465 case GS_STATE_DEBUG_PAUSED:
5466 case GS_STATE_OPTIONS_MENU:
5467 case GS_STATE_CONTROL_CONFIG:
5468 case GS_STATE_MISSION_LOG_SCROLLBACK:
5469 case GS_STATE_DEATH_DIED:
5470 case GS_STATE_SHOW_GOALS:
5471 case GS_STATE_HOTKEY_SCREEN:
5472 case GS_STATE_MULTI_PAUSED:
5473 case GS_STATE_TRAINING_PAUSED:
5474 case GS_STATE_EVENT_DEBUG:
5475 case GS_STATE_GAMEPLAY_HELP:
5476 end_mission = 0; // these events shouldn't end a mission
5480 switch (old_state) {
5481 case GS_STATE_BRIEFING:
5482 brief_stop_voices();
5483 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5484 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5485 && (new_state != GS_STATE_TEAM_SELECT) ){
5486 common_select_close();
5487 if ( new_state == GS_STATE_MAIN_MENU ) {
5488 freespace_stop_mission();
5492 // COMMAND LINE OPTION
5493 if (Cmdline_multi_stream_chat_to_file){
5494 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5495 cfclose(Multi_chat_stream);
5499 case GS_STATE_DEBRIEF:
5500 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5505 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5506 multi_df_debrief_close();
5509 case GS_STATE_LOAD_MISSION_MENU:
5510 mission_load_menu_close();
5513 case GS_STATE_SIMULATOR_ROOM:
5517 case GS_STATE_CAMPAIGN_ROOM:
5518 campaign_room_close();
5521 case GS_STATE_CMD_BRIEF:
5522 if (new_state == GS_STATE_OPTIONS_MENU) {
5527 if (new_state == GS_STATE_MAIN_MENU)
5528 freespace_stop_mission();
5533 case GS_STATE_RED_ALERT:
5537 case GS_STATE_SHIP_SELECT:
5538 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5539 new_state != GS_STATE_HOTKEY_SCREEN &&
5540 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5541 common_select_close();
5542 if ( new_state == GS_STATE_MAIN_MENU ) {
5543 freespace_stop_mission();
5548 case GS_STATE_WEAPON_SELECT:
5549 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5550 new_state != GS_STATE_HOTKEY_SCREEN &&
5551 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5552 common_select_close();
5553 if ( new_state == GS_STATE_MAIN_MENU ) {
5554 freespace_stop_mission();
5559 case GS_STATE_TEAM_SELECT:
5560 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5561 new_state != GS_STATE_HOTKEY_SCREEN &&
5562 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5563 common_select_close();
5564 if ( new_state == GS_STATE_MAIN_MENU ) {
5565 freespace_stop_mission();
5570 case GS_STATE_MAIN_MENU:
5571 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5578 case GS_STATE_OPTIONS_MENU:
5579 //game_start_time();
5580 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5581 multi_join_clear_game_list();
5583 options_menu_close();
5586 case GS_STATE_BARRACKS_MENU:
5587 if(new_state != GS_STATE_VIEW_MEDALS){
5592 case GS_STATE_MISSION_LOG_SCROLLBACK:
5593 hud_scrollback_close();
5596 case GS_STATE_TRAINING_MENU:
5597 training_menu_close();
5600 case GS_STATE_GAME_PLAY:
5601 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5602 player_save_target_and_weapon_link_prefs();
5603 game_stop_looped_sounds();
5606 sound_env_disable();
5607 joy_ff_stop_effects();
5609 // stop game time under certain conditions
5610 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5615 // shut down any recording or playing demos
5620 // when in multiplayer and going back to the main menu, send a leave game packet
5621 // right away (before calling stop mission). stop_mission was taking to long to
5622 // close mission down and I want people to get notified ASAP.
5623 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5624 multi_quit_game(PROMPT_NONE);
5627 freespace_stop_mission();
5628 Game_time_compression = F1_0;
5632 case GS_STATE_TECH_MENU:
5636 case GS_STATE_TRAINING_PAUSED:
5637 Training_num_lines = 0;
5638 // fall through to GS_STATE_GAME_PAUSED
5640 case GS_STATE_GAME_PAUSED:
5642 if ( end_mission ) {
5647 case GS_STATE_DEBUG_PAUSED:
5650 pause_debug_close();
5654 case GS_STATE_HUD_CONFIG:
5658 // join/start a game
5659 case GS_STATE_MULTI_JOIN_GAME:
5660 if(new_state != GS_STATE_OPTIONS_MENU){
5661 multi_join_game_close();
5665 case GS_STATE_MULTI_HOST_SETUP:
5666 case GS_STATE_MULTI_CLIENT_SETUP:
5667 // if this is just the host going into the options screen, don't do anything
5668 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5672 // close down the proper state
5673 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5674 multi_create_game_close();
5676 multi_game_client_setup_close();
5679 // COMMAND LINE OPTION
5680 if (Cmdline_multi_stream_chat_to_file){
5681 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5682 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5683 cfclose(Multi_chat_stream);
5688 case GS_STATE_CONTROL_CONFIG:
5689 control_config_close();
5692 case GS_STATE_DEATH_DIED:
5693 Game_mode &= ~GM_DEAD_DIED;
5695 // early end while respawning or blowing up in a multiplayer game
5696 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5698 freespace_stop_mission();
5702 case GS_STATE_DEATH_BLEW_UP:
5703 Game_mode &= ~GM_DEAD_BLEW_UP;
5705 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5706 // to determine if I should do anything.
5707 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5709 freespace_stop_mission();
5712 // if we are not respawing as an observer or as a player, our new state will not
5713 // be gameplay state.
5714 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5715 game_stop_time(); // hasn't been called yet!!
5716 freespace_stop_mission();
5722 case GS_STATE_CREDITS:
5726 case GS_STATE_VIEW_MEDALS:
5730 case GS_STATE_SHOW_GOALS:
5731 mission_show_goals_close();
5734 case GS_STATE_HOTKEY_SCREEN:
5735 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5736 mission_hotkey_close();
5740 case GS_STATE_MULTI_MISSION_SYNC:
5741 // if we're moving into the options menu, don't do anything
5742 if(new_state == GS_STATE_OPTIONS_MENU){
5746 Assert( Game_mode & GM_MULTIPLAYER );
5748 if ( new_state == GS_STATE_GAME_PLAY ){
5749 // palette_restore_palette();
5751 // change a couple of flags to indicate our state!!!
5752 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5753 send_netplayer_update_packet();
5755 // set the game mode
5756 Game_mode |= GM_IN_MISSION;
5760 case GS_STATE_VIEW_CUTSCENES:
5761 cutscenes_screen_close();
5764 case GS_STATE_MULTI_STD_WAIT:
5765 multi_standalone_wait_close();
5768 case GS_STATE_STANDALONE_MAIN:
5769 standalone_main_close();
5770 if(new_state == GS_STATE_MULTI_STD_WAIT){
5771 init_multiplayer_stats();
5775 case GS_STATE_MULTI_PAUSED:
5776 // if ( end_mission ){
5781 case GS_STATE_INGAME_PRE_JOIN:
5782 multi_ingame_select_close();
5785 case GS_STATE_STANDALONE_POSTGAME:
5786 multi_standalone_postgame_close();
5789 case GS_STATE_INITIAL_PLAYER_SELECT:
5790 player_select_close();
5793 case GS_STATE_MULTI_START_GAME:
5794 multi_start_game_close();
5797 case GS_STATE_MULTI_HOST_OPTIONS:
5798 multi_host_options_close();
5801 case GS_STATE_END_OF_CAMPAIGN:
5802 mission_campaign_end_close();
5805 case GS_STATE_LOOP_BRIEF:
5811 // Called when a state is being entered.
5812 // The current state is set to the state we're entering at
5813 // this point, and old_state is set to the state we're coming
5814 // from. You should never try to change the state
5815 // in here... if you think you need to, you probably really
5816 // need to post an event, not change the state.
5818 void game_enter_state( int old_state, int new_state )
5820 switch (new_state) {
5821 case GS_STATE_MAIN_MENU:
5822 // in multiplayer mode, be sure that we are not doing networking anymore.
5823 if ( Game_mode & GM_MULTIPLAYER ) {
5824 Assert( Net_player != NULL );
5825 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5828 Game_time_compression = F1_0;
5830 // determine which ship this guy is currently based on
5831 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5834 if (Player->on_bastion) {
5842 case GS_STATE_BRIEFING:
5843 main_hall_stop_music();
5844 main_hall_stop_ambient();
5846 if (Game_mode & GM_NORMAL) {
5847 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5848 // MWA: or from options or hotkey screens
5849 // JH: or if the command brief state already did this
5850 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5851 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5852 && (old_state != GS_STATE_CMD_BRIEF) ) {
5853 if ( !game_start_mission() ) // this should put us into a new state on failure!
5857 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5858 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5859 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5861 Game_time_compression = F1_0;
5863 if ( red_alert_mission() ) {
5864 gameseq_post_event(GS_EVENT_RED_ALERT);
5871 case GS_STATE_DEBRIEF:
5872 game_stop_looped_sounds();
5873 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5874 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5879 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5880 multi_df_debrief_init();
5883 case GS_STATE_LOAD_MISSION_MENU:
5884 mission_load_menu_init();
5887 case GS_STATE_SIMULATOR_ROOM:
5891 case GS_STATE_CAMPAIGN_ROOM:
5892 campaign_room_init();
5895 case GS_STATE_RED_ALERT:
5896 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5900 case GS_STATE_CMD_BRIEF: {
5901 int team_num = 0; // team number used as index for which cmd brief to use.
5903 if (old_state == GS_STATE_OPTIONS_MENU) {
5907 main_hall_stop_music();
5908 main_hall_stop_ambient();
5910 if (Game_mode & GM_NORMAL) {
5911 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5912 // MWA: or from options or hotkey screens
5913 // JH: or if the command brief state already did this
5914 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5915 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5916 if ( !game_start_mission() ) // this should put us into a new state on failure!
5921 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5922 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5923 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5925 cmd_brief_init(team_num);
5931 case GS_STATE_SHIP_SELECT:
5935 case GS_STATE_WEAPON_SELECT:
5936 weapon_select_init();
5939 case GS_STATE_TEAM_SELECT:
5943 case GS_STATE_GAME_PAUSED:
5948 case GS_STATE_DEBUG_PAUSED:
5949 // game_stop_time();
5950 // os_set_title("FreeSpace - PAUSED");
5953 case GS_STATE_TRAINING_PAUSED:
5960 case GS_STATE_OPTIONS_MENU:
5962 options_menu_init();
5965 case GS_STATE_GAME_PLAY:
5966 // coming from the gameplay state or the main menu, we might need to load the mission
5967 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5968 if ( !game_start_mission() ) // this should put us into a new state.
5973 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5974 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5975 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5976 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5977 (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) ) {
5978 // JAS: Used to do all paging here.
5982 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5986 main_hall_stop_music();
5987 main_hall_stop_ambient();
5988 event_music_first_pattern(); // start the first pattern
5991 // special code that restores player ship selection and weapons loadout when doing a quick start
5992 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5993 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5994 wss_direct_restore_loadout();
5998 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5999 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
6000 event_music_first_pattern(); // start the first pattern
6003 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
6004 event_music_first_pattern(); // start the first pattern
6006 player_restore_target_and_weapon_link_prefs();
6008 Game_mode |= GM_IN_MISSION;
6011 // required to truely make mouse deltas zeroed in debug mouse code
6012 void mouse_force_pos(int x, int y);
6013 if (!Is_standalone) {
6014 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6020 // only start time if in single player, or coming from multi wait state
6023 (Game_mode & GM_NORMAL) &&
6024 (old_state != GS_STATE_VIEW_CUTSCENES)
6026 (Game_mode & GM_MULTIPLAYER) && (
6027 (old_state == GS_STATE_MULTI_PAUSED) ||
6028 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6034 // when coming from the multi paused state, reset the timestamps
6035 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6036 multi_reset_timestamps();
6039 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6040 // initialize all object update details
6041 multi_oo_gameplay_init();
6044 // under certain circumstances, the server should reset the object update rate limiting stuff
6045 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6046 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6048 // reinitialize the rate limiting system for all clients
6049 multi_oo_rate_init_all();
6052 // multiplayer clients should always re-initialize their control info rate limiting system
6053 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6054 multi_oo_rate_init_all();
6058 if(Game_mode & GM_MULTIPLAYER){
6059 multi_ping_reset_players();
6062 Game_subspace_effect = 0;
6063 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6064 Game_subspace_effect = 1;
6065 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6066 game_start_subspace_ambient_sound();
6070 sound_env_set(&Game_sound_env);
6071 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6073 // clear multiplayer button info i
6074 extern button_info Multi_ship_status_bi;
6075 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6078 case GS_STATE_HUD_CONFIG:
6082 case GS_STATE_MULTI_JOIN_GAME:
6083 multi_join_clear_game_list();
6085 if (old_state != GS_STATE_OPTIONS_MENU) {
6086 multi_join_game_init();
6091 case GS_STATE_MULTI_HOST_SETUP:
6092 // don't reinitialize if we're coming back from the host options screen
6093 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6094 multi_create_game_init();
6099 case GS_STATE_MULTI_CLIENT_SETUP:
6100 if (old_state != GS_STATE_OPTIONS_MENU) {
6101 multi_game_client_setup_init();
6106 case GS_STATE_CONTROL_CONFIG:
6107 control_config_init();
6110 case GS_STATE_TECH_MENU:
6114 case GS_STATE_BARRACKS_MENU:
6115 if(old_state != GS_STATE_VIEW_MEDALS){
6120 case GS_STATE_MISSION_LOG_SCROLLBACK:
6121 hud_scrollback_init();
6124 case GS_STATE_DEATH_DIED:
6125 Player_died_time = timestamp(10);
6127 if(!(Game_mode & GM_MULTIPLAYER)){
6128 player_show_death_message();
6130 Game_mode |= GM_DEAD_DIED;
6133 case GS_STATE_DEATH_BLEW_UP:
6134 if ( !popupdead_is_active() ) {
6135 Player_ai->target_objnum = -1;
6138 // stop any local EMP effect
6141 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6142 Game_mode |= GM_DEAD_BLEW_UP;
6143 Show_viewing_from_self = 0;
6145 // timestamp how long we should wait before displaying the died popup
6146 if ( !popupdead_is_active() ) {
6147 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6151 case GS_STATE_GAMEPLAY_HELP:
6152 gameplay_help_init();
6155 case GS_STATE_CREDITS:
6156 main_hall_stop_music();
6157 main_hall_stop_ambient();
6161 case GS_STATE_VIEW_MEDALS:
6162 medal_main_init(Player);
6165 case GS_STATE_SHOW_GOALS:
6166 mission_show_goals_init();
6169 case GS_STATE_HOTKEY_SCREEN:
6170 mission_hotkey_init();
6173 case GS_STATE_MULTI_MISSION_SYNC:
6174 // if we're coming from the options screen, don't do any
6175 if(old_state == GS_STATE_OPTIONS_MENU){
6179 switch(Multi_sync_mode){
6180 case MULTI_SYNC_PRE_BRIEFING:
6181 // if moving from game forming to the team select state
6184 case MULTI_SYNC_POST_BRIEFING:
6185 // if moving from briefing into the mission itself
6188 // tell everyone that we're now loading data
6189 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6190 send_netplayer_update_packet();
6192 // JAS: Used to do all paging here!!!!
6194 Net_player->state = NETPLAYER_STATE_WAITING;
6195 send_netplayer_update_packet();
6197 Game_time_compression = F1_0;
6199 case MULTI_SYNC_INGAME:
6205 case GS_STATE_VIEW_CUTSCENES:
6206 cutscenes_screen_init();
6209 case GS_STATE_MULTI_STD_WAIT:
6210 multi_standalone_wait_init();
6213 case GS_STATE_STANDALONE_MAIN:
6214 // don't initialize if we're coming from one of these 2 states unless there are no
6215 // players left (reset situation)
6216 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6217 standalone_main_init();
6221 case GS_STATE_MULTI_PAUSED:
6225 case GS_STATE_INGAME_PRE_JOIN:
6226 multi_ingame_select_init();
6229 case GS_STATE_STANDALONE_POSTGAME:
6230 multi_standalone_postgame_init();
6233 case GS_STATE_INITIAL_PLAYER_SELECT:
6234 player_select_init();
6237 case GS_STATE_MULTI_START_GAME:
6238 multi_start_game_init();
6241 case GS_STATE_MULTI_HOST_OPTIONS:
6242 multi_host_options_init();
6245 case GS_STATE_END_OF_CAMPAIGN:
6246 mission_campaign_end_init();
6249 case GS_STATE_LOOP_BRIEF:
6256 // do stuff that may need to be done regardless of state
6257 void game_do_state_common(int state,int no_networking)
6259 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6260 snd_do_frame(); // update sound system
6261 event_music_do_frame(); // music needs to play across many states
6263 multi_log_process();
6265 if (no_networking) {
6269 // maybe do a multiplayer frame based on game mode and state type
6270 if (Game_mode & GM_MULTIPLAYER) {
6272 case GS_STATE_OPTIONS_MENU:
6273 case GS_STATE_GAMEPLAY_HELP:
6274 case GS_STATE_HOTKEY_SCREEN:
6275 case GS_STATE_HUD_CONFIG:
6276 case GS_STATE_CONTROL_CONFIG:
6277 case GS_STATE_MISSION_LOG_SCROLLBACK:
6278 case GS_STATE_SHOW_GOALS:
6279 case GS_STATE_VIEW_CUTSCENES:
6280 case GS_STATE_EVENT_DEBUG:
6281 multi_maybe_do_frame();
6285 game_do_networking();
6289 // Called once a frame.
6290 // You should never try to change the state
6291 // in here... if you think you need to, you probably really
6292 // need to post an event, not change the state.
6293 int Game_do_state_should_skip = 0;
6294 void game_do_state(int state)
6296 // always lets the do_state_common() function determine if the state should be skipped
6297 Game_do_state_should_skip = 0;
6299 // legal to set the should skip state anywhere in this function
6300 game_do_state_common(state); // do stuff that may need to be done regardless of state
6302 if(Game_do_state_should_skip){
6307 case GS_STATE_MAIN_MENU:
6308 game_set_frametime(GS_STATE_MAIN_MENU);
6309 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6312 main_hall_do(flFrametime);
6316 case GS_STATE_OPTIONS_MENU:
6317 game_set_frametime(GS_STATE_OPTIONS_MENU);
6318 options_menu_do_frame(flFrametime);
6321 case GS_STATE_BARRACKS_MENU:
6322 game_set_frametime(GS_STATE_BARRACKS_MENU);
6323 barracks_do_frame(flFrametime);
6326 case GS_STATE_TRAINING_MENU:
6327 game_set_frametime(GS_STATE_TRAINING_MENU);
6328 training_menu_do_frame(flFrametime);
6331 case GS_STATE_TECH_MENU:
6332 game_set_frametime(GS_STATE_TECH_MENU);
6333 techroom_do_frame(flFrametime);
6336 case GS_STATE_GAMEPLAY_HELP:
6337 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6338 gameplay_help_do_frame(flFrametime);
6341 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6345 case GS_STATE_GAME_PAUSED:
6349 case GS_STATE_DEBUG_PAUSED:
6351 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6356 case GS_STATE_TRAINING_PAUSED:
6357 game_training_pause_do();
6360 case GS_STATE_LOAD_MISSION_MENU:
6361 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6362 mission_load_menu_do();
6365 case GS_STATE_BRIEFING:
6366 game_set_frametime(GS_STATE_BRIEFING);
6367 brief_do_frame(flFrametime);
6370 case GS_STATE_DEBRIEF:
6371 game_set_frametime(GS_STATE_DEBRIEF);
6372 debrief_do_frame(flFrametime);
6375 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6376 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6377 multi_df_debrief_do();
6380 case GS_STATE_SHIP_SELECT:
6381 game_set_frametime(GS_STATE_SHIP_SELECT);
6382 ship_select_do(flFrametime);
6385 case GS_STATE_WEAPON_SELECT:
6386 game_set_frametime(GS_STATE_WEAPON_SELECT);
6387 weapon_select_do(flFrametime);
6390 case GS_STATE_MISSION_LOG_SCROLLBACK:
6391 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6392 hud_scrollback_do_frame(flFrametime);
6395 case GS_STATE_HUD_CONFIG:
6396 game_set_frametime(GS_STATE_HUD_CONFIG);
6397 hud_config_do_frame(flFrametime);
6400 case GS_STATE_MULTI_JOIN_GAME:
6401 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6402 multi_join_game_do_frame();
6405 case GS_STATE_MULTI_HOST_SETUP:
6406 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6407 multi_create_game_do();
6410 case GS_STATE_MULTI_CLIENT_SETUP:
6411 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6412 multi_game_client_setup_do_frame();
6415 case GS_STATE_CONTROL_CONFIG:
6416 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6417 control_config_do_frame(flFrametime);
6420 case GS_STATE_DEATH_DIED:
6424 case GS_STATE_DEATH_BLEW_UP:
6428 case GS_STATE_SIMULATOR_ROOM:
6429 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6430 sim_room_do_frame(flFrametime);
6433 case GS_STATE_CAMPAIGN_ROOM:
6434 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6435 campaign_room_do_frame(flFrametime);
6438 case GS_STATE_RED_ALERT:
6439 game_set_frametime(GS_STATE_RED_ALERT);
6440 red_alert_do_frame(flFrametime);
6443 case GS_STATE_CMD_BRIEF:
6444 game_set_frametime(GS_STATE_CMD_BRIEF);
6445 cmd_brief_do_frame(flFrametime);
6448 case GS_STATE_CREDITS:
6449 game_set_frametime(GS_STATE_CREDITS);
6450 credits_do_frame(flFrametime);
6453 case GS_STATE_VIEW_MEDALS:
6454 game_set_frametime(GS_STATE_VIEW_MEDALS);
6458 case GS_STATE_SHOW_GOALS:
6459 game_set_frametime(GS_STATE_SHOW_GOALS);
6460 mission_show_goals_do_frame(flFrametime);
6463 case GS_STATE_HOTKEY_SCREEN:
6464 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6465 mission_hotkey_do_frame(flFrametime);
6468 case GS_STATE_VIEW_CUTSCENES:
6469 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6470 cutscenes_screen_do_frame();
6473 case GS_STATE_MULTI_STD_WAIT:
6474 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6475 multi_standalone_wait_do();
6478 case GS_STATE_STANDALONE_MAIN:
6479 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6480 standalone_main_do();
6483 case GS_STATE_MULTI_PAUSED:
6484 game_set_frametime(GS_STATE_MULTI_PAUSED);
6488 case GS_STATE_TEAM_SELECT:
6489 game_set_frametime(GS_STATE_TEAM_SELECT);
6493 case GS_STATE_INGAME_PRE_JOIN:
6494 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6495 multi_ingame_select_do();
6498 case GS_STATE_EVENT_DEBUG:
6500 game_set_frametime(GS_STATE_EVENT_DEBUG);
6501 game_show_event_debug(flFrametime);
6505 case GS_STATE_STANDALONE_POSTGAME:
6506 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6507 multi_standalone_postgame_do();
6510 case GS_STATE_INITIAL_PLAYER_SELECT:
6511 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6515 case GS_STATE_MULTI_MISSION_SYNC:
6516 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6520 case GS_STATE_MULTI_START_GAME:
6521 game_set_frametime(GS_STATE_MULTI_START_GAME);
6522 multi_start_game_do();
6525 case GS_STATE_MULTI_HOST_OPTIONS:
6526 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6527 multi_host_options_do();
6530 case GS_STATE_END_OF_CAMPAIGN:
6531 mission_campaign_end_do();
6534 case GS_STATE_END_DEMO:
6535 game_set_frametime(GS_STATE_END_DEMO);
6536 end_demo_campaign_do();
6539 case GS_STATE_LOOP_BRIEF:
6540 game_set_frametime(GS_STATE_LOOP_BRIEF);
6544 } // end switch(gs_current_state)
6548 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6549 int game_do_ram_check(int ram_in_bytes)
6551 if ( ram_in_bytes < 30*1024*1024 ) {
6552 int allowed_to_run = 1;
6553 if ( ram_in_bytes < 25*1024*1024 ) {
6558 int Freespace_total_ram_MB;
6559 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6561 if ( allowed_to_run ) {
6563 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);
6568 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6569 if ( msgbox_rval == IDCANCEL ) {
6576 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);
6578 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6589 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6590 // If so, copy it over and remove the update directory.
6591 void game_maybe_update_launcher(char *exe_dir)
6594 char src_filename[MAX_PATH];
6595 char dest_filename[MAX_PATH];
6597 strcpy(src_filename, exe_dir);
6598 strcat(src_filename, NOX("\\update\\freespace.exe"));
6600 strcpy(dest_filename, exe_dir);
6601 strcat(dest_filename, NOX("\\freespace.exe"));
6603 // see if src_filename exists
6605 fp = fopen(src_filename, "rb");
6611 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6613 // copy updated freespace.exe to freespace exe dir
6614 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6615 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 );
6619 // delete the file in the update directory
6620 DeleteFile(src_filename);
6622 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6623 char update_dir[MAX_PATH];
6624 strcpy(update_dir, exe_dir);
6625 strcat(update_dir, NOX("\\update"));
6626 RemoveDirectory(update_dir);
6632 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6636 int sub_total_destroyed = 0;
6640 // get the total for all his children
6641 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6642 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6645 // find the # of faces for this _individual_ object
6646 total = submodel_get_num_polys(model_num, sm);
6647 if(strstr(pm->submodel[sm].name, "-destroyed")){
6648 sub_total_destroyed = total;
6652 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6655 *out_total += total + sub_total;
6656 *out_destroyed_total += sub_total_destroyed;
6659 #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);
6660 void game_spew_pof_info()
6662 char *pof_list[1000];
6665 int idx, model_num, i, j;
6667 int total, root_total, model_total, destroyed_total, counted;
6671 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6673 // spew info on all the pofs
6679 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6684 for(idx=0; idx<num_files; idx++, counted++){
6685 sprintf(str, "%s.pof", pof_list[idx]);
6686 model_num = model_load(str, 0, NULL);
6688 pm = model_get(model_num);
6690 // if we have a real model
6695 // go through and print all raw submodels
6696 cfputs("RAW\n", out);
6699 for (i=0; i<pm->n_models; i++) {
6700 total = submodel_get_num_polys(model_num, i);
6702 model_total += total;
6703 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6706 sprintf(str, "Model total %d\n", model_total);
6709 // now go through and do it by LOD
6710 cfputs("BY LOD\n\n", out);
6711 for(i=0; i<pm->n_detail_levels; i++){
6712 sprintf(str, "LOD %d\n", i);
6716 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6718 destroyed_total = 0;
6719 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6720 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6723 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6726 sprintf(str, "TOTAL: %d\n", total + root_total);
6728 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6730 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6733 cfputs("------------------------------------------------------------------------\n\n", out);
6737 if(counted >= MAX_POLYGON_MODELS - 5){
6750 game_spew_pof_info();
6753 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6758 // Don't let more than one instance of Freespace run.
6759 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6761 SetForegroundWindow(hwnd);
6766 // Find out how much RAM is on this machine
6769 ms.dwLength = sizeof(MEMORYSTATUS);
6770 GlobalMemoryStatus(&ms);
6771 Freespace_total_ram = ms.dwTotalPhys;
6773 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6777 if ( ms.dwTotalVirtual < 1024 ) {
6778 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6782 if (!vm_init(24*1024*1024)) {
6783 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 );
6787 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6789 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);
6797 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6798 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6799 seem worth bothering with.
6803 lResult = RegOpenKeyEx(
6804 HKEY_LOCAL_MACHINE, // Where it is
6805 "Software\\Microsoft\\DirectX", // name of key
6806 NULL, // DWORD reserved
6807 KEY_QUERY_VALUE, // Allows all changes
6808 &hKey // Location to store key
6811 if (lResult == ERROR_SUCCESS) {
6813 DWORD dwType, dwLen;
6816 lResult = RegQueryValueEx(
6817 hKey, // Handle to key
6818 "Version", // The values name
6819 NULL, // DWORD reserved
6820 &dwType, // What kind it is
6821 (ubyte *) version, // value to set
6822 &dwLen // How many bytes to set
6825 if (lResult == ERROR_SUCCESS) {
6826 dx_version = atoi(strstr(version, ".") + 1);
6830 DWORD dwType, dwLen;
6833 lResult = RegQueryValueEx(
6834 hKey, // Handle to key
6835 "InstalledVersion", // The values name
6836 NULL, // DWORD reserved
6837 &dwType, // What kind it is
6838 (ubyte *) &val, // value to set
6839 &dwLen // How many bytes to set
6842 if (lResult == ERROR_SUCCESS) {
6850 if (dx_version < 3) {
6851 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6852 "latest version of DirectX at:\n\n"
6853 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6855 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6856 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6861 //=====================================================
6862 // Make sure we're running in the right directory.
6866 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6867 char *p = exe_dir + strlen(exe_dir);
6869 // chop off the filename
6870 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6876 if ( strlen(exe_dir) > 0 ) {
6877 SetCurrentDirectory(exe_dir);
6880 // check for updated freespace.exe
6881 game_maybe_update_launcher(exe_dir);
6889 extern void windebug_memwatch_init();
6890 windebug_memwatch_init();
6894 parse_cmdline(szCmdLine);
6896 #ifdef STANDALONE_ONLY_BUILD
6898 nprintf(("Network", "Standalone running"));
6901 nprintf(("Network", "Standalone running"));
6909 // maybe spew pof stuff
6910 if(Cmdline_spew_pof_info){
6911 game_spew_pof_info();
6916 // non-demo, non-standalone, play the intro movie
6921 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) ){
6923 #if defined(OEM_BUILD)
6924 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6926 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6927 #endif // defined(OEM_BUILD)
6932 if ( !Is_standalone ) {
6934 // release -- movies always play
6937 // 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
6938 movie_play( NOX("intro.mve"), 0 );
6940 // debug version, movie will only play with -showmovies
6941 #elif !defined(NDEBUG)
6943 movie_play( NOX("intro.mve"), 0);
6946 if ( Cmdline_show_movies )
6947 movie_play( NOX("intro.mve"), 0 );
6956 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6958 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6962 // only important for non THREADED mode
6965 state = gameseq_process_events();
6966 if ( state == GS_STATE_QUIT_GAME ){
6973 demo_upsell_show_screens();
6975 #elif defined(OEM_BUILD)
6976 // show upsell screens on exit
6977 oem_upsell_show_screens();
6984 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6990 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6992 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6994 // Do nothing here - RecordExceptionInfo() has already done
6995 // everything that is needed. Actually this code won't even
6996 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6997 // the __except clause.
7001 nprintf(("WinMain", "exceptions shall fall through"));
7003 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7009 // launcher the fslauncher program on exit
7010 void game_launch_launcher_on_exit()
7014 PROCESS_INFORMATION pi;
7015 char cmd_line[2048];
7016 char original_path[1024] = "";
7018 memset( &si, 0, sizeof(STARTUPINFO) );
7022 _getcwd(original_path, 1023);
7024 // set up command line
7025 strcpy(cmd_line, original_path);
7026 strcat(cmd_line, "\\");
7027 strcat(cmd_line, LAUNCHER_FNAME);
7028 strcat(cmd_line, " -straight_to_update");
7030 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7031 cmd_line, // pointer to command line string
7032 NULL, // pointer to process security attributes
7033 NULL, // pointer to thread security attributes
7034 FALSE, // handle inheritance flag
7035 CREATE_DEFAULT_ERROR_MODE, // creation flags
7036 NULL, // pointer to new environment block
7037 NULL, // pointer to current directory name
7038 &si, // pointer to STARTUPINFO
7039 &pi // pointer to PROCESS_INFORMATION
7041 // to eliminate build warnings
7051 // This function is called when FreeSpace terminates normally.
7053 void game_shutdown(void)
7059 // don't ever flip a page on the standalone!
7060 if(!(Game_mode & GM_STANDALONE_SERVER)){
7066 // if the player has left the "player select" screen and quit the game without actually choosing
7067 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7068 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7072 // load up common multiplayer icons
7073 multi_unload_common_icons();
7075 shockwave_close(); // release any memory used by shockwave system
7076 fireball_close(); // free fireball system
7077 ship_close(); // free any memory that was allocated for the ships
7078 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7079 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7080 bm_unload_all(); // free bitmaps
7081 mission_campaign_close(); // close out the campaign stuff
7082 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7084 #ifdef MULTI_USE_LAG
7088 // the menu close functions will unload the bitmaps if they were displayed during the game
7089 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7092 training_menu_close();
7095 extern void joy_close();
7098 audiostream_close();
7100 event_music_close();
7104 // HACKITY HACK HACK
7105 // if this flag is set, we should be firing up the launcher when exiting freespace
7106 extern int Multi_update_fireup_launcher_on_exit;
7107 if(Multi_update_fireup_launcher_on_exit){
7108 game_launch_launcher_on_exit();
7112 // game_stop_looped_sounds()
7114 // This function will call the appropriate stop looped sound functions for those
7115 // modules which use looping sounds. It is not enough just to stop a looping sound
7116 // at the DirectSound level, the game is keeping track of looping sounds, and this
7117 // function is used to inform the game that looping sounds are being halted.
7119 void game_stop_looped_sounds()
7121 hud_stop_looped_locking_sounds();
7122 hud_stop_looped_engine_sounds();
7123 afterburner_stop_sounds();
7124 player_stop_looped_sounds();
7125 obj_snd_stop_all(); // stop all object-linked persistant sounds
7126 game_stop_subspace_ambient_sound();
7127 snd_stop(Radar_static_looping);
7128 Radar_static_looping = -1;
7129 snd_stop(Target_static_looping);
7130 shipfx_stop_engine_wash_sound();
7131 Target_static_looping = -1;
7134 //////////////////////////////////////////////////////////////////////////
7136 // Code for supporting an animating mouse pointer
7139 //////////////////////////////////////////////////////////////////////////
7141 typedef struct animating_obj
7150 static animating_obj Animating_mouse;
7152 // ----------------------------------------------------------------------------
7153 // init_animating_pointer()
7155 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7156 // gets properly initialized
7158 void init_animating_pointer()
7160 Animating_mouse.first_frame = -1;
7161 Animating_mouse.num_frames = 0;
7162 Animating_mouse.current_frame = -1;
7163 Animating_mouse.time = 0.0f;
7164 Animating_mouse.elapsed_time = 0.0f;
7167 // ----------------------------------------------------------------------------
7168 // load_animating_pointer()
7170 // Called at game init to load in the frames for the animating mouse pointer
7172 // input: filename => filename of animation file that holds the animation
7174 void load_animating_pointer(char *filename, int dx, int dy)
7179 init_animating_pointer();
7181 am = &Animating_mouse;
7182 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7183 if ( am->first_frame == -1 )
7184 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7185 am->current_frame = 0;
7186 am->time = am->num_frames / i2fl(fps);
7189 // ----------------------------------------------------------------------------
7190 // unload_animating_pointer()
7192 // Called at game shutdown to free the memory used to store the animation frames
7194 void unload_animating_pointer()
7199 am = &Animating_mouse;
7200 for ( i = 0; i < am->num_frames; i++ ) {
7201 Assert( (am->first_frame+i) >= 0 );
7202 bm_release(am->first_frame + i);
7205 am->first_frame = -1;
7207 am->current_frame = -1;
7210 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7211 void game_render_mouse(float frametime)
7216 // if animating cursor exists, play the next frame
7217 am = &Animating_mouse;
7218 if ( am->first_frame != -1 ) {
7219 mouse_get_pos(&mx, &my);
7220 am->elapsed_time += frametime;
7221 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7222 if ( am->current_frame >= am->num_frames ) {
7223 am->current_frame = 0;
7224 am->elapsed_time = 0.0f;
7226 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7230 // ----------------------------------------------------------------------------
7231 // game_maybe_draw_mouse()
7233 // determines whether to draw the mouse pointer at all, and what frame of
7234 // animation to use if the mouse is animating
7236 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7238 // input: frametime => elapsed frame time in seconds since last call
7240 void game_maybe_draw_mouse(float frametime)
7244 game_state = gameseq_get_state();
7246 switch ( game_state ) {
7247 case GS_STATE_GAME_PAUSED:
7248 // case GS_STATE_MULTI_PAUSED:
7249 case GS_STATE_GAME_PLAY:
7250 case GS_STATE_DEATH_DIED:
7251 case GS_STATE_DEATH_BLEW_UP:
7252 if ( popup_active() || popupdead_is_active() ) {
7264 if ( !Mouse_hidden )
7265 game_render_mouse(frametime);
7269 void game_do_training_checks()
7273 waypoint_list *wplp;
7275 if (Training_context & TRAINING_CONTEXT_SPEED) {
7276 s = (int) Player_obj->phys_info.fspeed;
7277 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7278 if (!Training_context_speed_set) {
7279 Training_context_speed_set = 1;
7280 Training_context_speed_timestamp = timestamp();
7284 Training_context_speed_set = 0;
7287 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7288 wplp = &Waypoint_lists[Training_context_path];
7289 if (wplp->count > Training_context_goal_waypoint) {
7290 i = Training_context_goal_waypoint;
7292 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7293 if (d <= Training_context_distance) {
7294 Training_context_at_waypoint = i;
7295 if (Training_context_goal_waypoint == i) {
7296 Training_context_goal_waypoint++;
7297 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7304 if (i == wplp->count)
7307 } while (i != Training_context_goal_waypoint);
7311 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7312 Players_target = Player_ai->target_objnum;
7313 Players_targeted_subsys = Player_ai->targeted_subsys;
7314 Players_target_timestamp = timestamp();
7318 /////////// Following is for event debug view screen
7322 #define EVENT_DEBUG_MAX 5000
7323 #define EVENT_DEBUG_EVENT 0x8000
7325 int Event_debug_index[EVENT_DEBUG_MAX];
7328 void game_add_event_debug_index(int n, int indent)
7330 if (ED_count < EVENT_DEBUG_MAX)
7331 Event_debug_index[ED_count++] = n | (indent << 16);
7334 void game_add_event_debug_sexp(int n, int indent)
7339 if (Sexp_nodes[n].first >= 0) {
7340 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7341 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7345 game_add_event_debug_index(n, indent);
7346 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7347 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7349 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7352 void game_event_debug_init()
7357 for (e=0; e<Num_mission_events; e++) {
7358 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7359 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7363 void game_show_event_debug(float frametime)
7367 int font_height, font_width;
7369 static int scroll_offset = 0;
7371 k = game_check_key();
7377 if (scroll_offset < 0)
7387 scroll_offset -= 20;
7388 if (scroll_offset < 0)
7393 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7397 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7403 gr_set_color_fast(&Color_bright);
7405 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7407 gr_set_color_fast(&Color_normal);
7409 gr_get_string_size(&font_width, &font_height, NOX("test"));
7410 y_max = gr_screen.max_h - font_height - 5;
7414 while (k < ED_count) {
7415 if (y_index > y_max)
7418 z = Event_debug_index[k];
7419 if (z & EVENT_DEBUG_EVENT) {
7421 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7422 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7423 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7424 Mission_events[z].repeat_count, Mission_events[z].interval);
7432 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7433 switch (Sexp_nodes[z & 0x7fff].value) {
7435 strcat(buf, NOX(" (True)"));
7439 strcat(buf, NOX(" (False)"));
7442 case SEXP_KNOWN_TRUE:
7443 strcat(buf, NOX(" (Always true)"));
7446 case SEXP_KNOWN_FALSE:
7447 strcat(buf, NOX(" (Always false)"));
7450 case SEXP_CANT_EVAL:
7451 strcat(buf, NOX(" (Can't eval)"));
7455 case SEXP_NAN_FOREVER:
7456 strcat(buf, NOX(" (Not a number)"));
7461 gr_printf(10, y_index, buf);
7462 y_index += font_height;
7475 extern int Tmap_npixels;
7477 int Tmap_num_too_big = 0;
7478 int Num_models_needing_splitting = 0;
7480 void Time_model( int modelnum )
7482 // mprintf(( "Timing ship '%s'\n", si->name ));
7484 vector eye_pos, model_pos;
7485 matrix eye_orient, model_orient;
7487 polymodel *pm = model_get( modelnum );
7489 int l = strlen(pm->filename);
7491 if ( (l == '/') || (l=='\\') || (l==':')) {
7497 char *pof_file = &pm->filename[l];
7499 int model_needs_splitting = 0;
7501 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7503 for (i=0; i<pm->n_textures; i++ ) {
7504 char filename[1024];
7507 int bmp_num = pm->original_textures[i];
7508 if ( bmp_num > -1 ) {
7509 bm_get_palette(pm->original_textures[i], pal, filename );
7511 bm_get_info( pm->original_textures[i],&w, &h );
7514 if ( (w > 512) || (h > 512) ) {
7515 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7517 model_needs_splitting++;
7520 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7524 if ( model_needs_splitting ) {
7525 Num_models_needing_splitting++;
7527 eye_orient = model_orient = vmd_identity_matrix;
7528 eye_pos = model_pos = vmd_zero_vector;
7530 eye_pos.xyz.z = -pm->rad*2.0f;
7532 vector eye_to_model;
7534 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7535 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7537 fix t1 = timer_get_fixed_seconds();
7540 ta.p = ta.b = ta.h = 0.0f;
7545 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7547 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7549 modelstats_num_polys = modelstats_num_verts = 0;
7551 while( ta.h < PI2 ) {
7554 vm_angles_2_matrix(&m1, &ta );
7555 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7562 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7564 model_clear_instance( modelnum );
7565 model_set_detail_level(0); // use highest detail level
7566 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7574 int k = key_inkey();
7575 if ( k == KEY_ESC ) {
7580 fix t2 = timer_get_fixed_seconds();
7582 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7583 //bitmaps_used_this_frame /= framecount;
7585 modelstats_num_polys /= framecount;
7586 modelstats_num_verts /= framecount;
7588 Tmap_npixels /=framecount;
7591 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7592 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 );
7593 // 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 );
7599 int Time_models = 0;
7600 DCF_BOOL( time_models, Time_models );
7602 void Do_model_timings_test()
7606 if ( !Time_models ) return;
7608 mprintf(( "Timing models!\n" ));
7612 ubyte model_used[MAX_POLYGON_MODELS];
7613 int model_id[MAX_POLYGON_MODELS];
7614 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7619 for (i=0; i<Num_ship_types; i++ ) {
7620 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7622 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7623 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7626 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7627 if ( !Texture_fp ) return;
7629 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7630 if ( !Time_fp ) return;
7632 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7633 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7635 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7636 if ( model_used[i] ) {
7637 Time_model( model_id[i] );
7641 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7642 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7651 // Call this function when you want to inform the player that a feature is not
7652 // enabled in the DEMO version of FreSpace
7653 void game_feature_not_in_demo_popup()
7655 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7658 // format the specified time (fixed point) into a nice string
7659 void game_format_time(fix m_time,char *time_str)
7662 int hours,minutes,seconds;
7665 mtime = f2fl(m_time);
7667 // get the hours, minutes and seconds
7668 hours = (int)(mtime / 3600.0f);
7670 mtime -= (3600.0f * (float)hours);
7672 seconds = (int)mtime%60;
7673 minutes = (int)mtime/60;
7675 // print the hour if necessary
7677 sprintf(time_str,XSTR( "%d:", 201),hours);
7678 // if there are less than 10 minutes, print a leading 0
7680 strcpy(tmp,NOX("0"));
7681 strcat(time_str,tmp);
7685 // print the minutes
7687 sprintf(tmp,XSTR( "%d:", 201),minutes);
7688 strcat(time_str,tmp);
7690 sprintf(time_str,XSTR( "%d:", 201),minutes);
7693 // print the seconds
7695 strcpy(tmp,NOX("0"));
7696 strcat(time_str,tmp);
7698 sprintf(tmp,"%d",seconds);
7699 strcat(time_str,tmp);
7702 // Stuff version string in *str.
7703 void get_version_string(char *str)
7706 if ( FS_VERSION_BUILD == 0 ) {
7707 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7709 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7712 #if defined (FS2_DEMO)
7714 #elif defined (OEM_BUILD)
7715 strcat(str, " (OEM)");
7721 char myname[_MAX_PATH];
7722 int namelen, major, minor, build, waste;
7723 unsigned int buf_size;
7729 // Find my EXE file name
7730 hMod = GetModuleHandle(NULL);
7731 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7733 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7734 infop = (char *)malloc(version_size);
7735 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7737 // get the product version
7738 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7739 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7741 sprintf(str,"Dv%d.%02d",major, minor);
7743 sprintf(str,"v%d.%02d",major, minor);
7748 void get_version_string_short(char *str)
7750 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7753 // ----------------------------------------------------------------
7755 // OEM UPSELL SCREENS BEGIN
7757 // ----------------------------------------------------------------
7758 #if defined(OEM_BUILD)
7760 #define NUM_OEM_UPSELL_SCREENS 3
7761 #define OEM_UPSELL_SCREEN_DELAY 10000
7763 static int Oem_upsell_bitmaps_loaded = 0;
7764 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7765 static int Oem_upsell_screen_number = 0;
7766 static int Oem_upsell_show_next_bitmap_time;
7769 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7782 static int Oem_normal_cursor = -1;
7783 static int Oem_web_cursor = -1;
7784 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7785 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7787 void oem_upsell_next_screen()
7789 Oem_upsell_screen_number++;
7790 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7791 // extra long delay, mouse shown on last upsell
7792 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7796 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7800 void oem_upsell_load_bitmaps()
7804 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7805 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7809 void oem_upsell_unload_bitmaps()
7813 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7814 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7815 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7820 Oem_upsell_bitmaps_loaded = 0;
7823 // clickable hotspot on 3rd OEM upsell screen
7824 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7826 28, 350, 287, 96 // x, y, w, h
7829 45, 561, 460, 152 // x, y, w, h
7833 void oem_upsell_show_screens()
7835 int current_time, k;
7838 if ( !Oem_upsell_bitmaps_loaded ) {
7839 oem_upsell_load_bitmaps();
7840 Oem_upsell_bitmaps_loaded = 1;
7843 // may use upsell screens more than once
7844 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7845 Oem_upsell_screen_number = 0;
7851 int nframes; // used to pass, not really needed (should be 1)
7852 Oem_normal_cursor = gr_get_cursor_bitmap();
7853 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7854 Assert(Oem_web_cursor >= 0);
7855 if (Oem_web_cursor < 0) {
7856 Oem_web_cursor = Oem_normal_cursor;
7861 //oem_reset_trailer_timer();
7863 current_time = timer_get_milliseconds();
7868 // advance screen on keypress or timeout
7869 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7870 oem_upsell_next_screen();
7873 // check if we are done
7874 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7875 Oem_upsell_screen_number--;
7878 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7883 // show me the upsell
7884 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7885 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7889 // if this is the 3rd upsell, make it clickable, d00d
7890 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7892 int button_state = mouse_get_pos(&mx, &my);
7893 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])
7894 && (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]) )
7897 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7900 if (button_state & MOUSE_LEFT_BUTTON) {
7902 multi_pxo_url(OEM_UPSELL_URL);
7906 // switch cursor back to normal one
7907 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7912 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7922 oem_upsell_unload_bitmaps();
7924 // switch cursor back to normal one
7925 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7929 #endif // defined(OEM_BUILD)
7930 // ----------------------------------------------------------------
7932 // OEM UPSELL SCREENS END
7934 // ----------------------------------------------------------------
7938 // ----------------------------------------------------------------
7940 // DEMO UPSELL SCREENS BEGIN
7942 // ----------------------------------------------------------------
7946 //#define NUM_DEMO_UPSELL_SCREENS 4
7948 #define NUM_DEMO_UPSELL_SCREENS 2
7949 #define DEMO_UPSELL_SCREEN_DELAY 3000
7951 static int Demo_upsell_bitmaps_loaded = 0;
7952 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7953 static int Demo_upsell_screen_number = 0;
7954 static int Demo_upsell_show_next_bitmap_time;
7957 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7970 void demo_upsell_next_screen()
7972 Demo_upsell_screen_number++;
7973 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7974 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7976 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7980 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7981 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7982 #ifndef HARDWARE_ONLY
7983 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7990 void demo_upsell_load_bitmaps()
7994 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7995 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7999 void demo_upsell_unload_bitmaps()
8003 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8004 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8005 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8010 Demo_upsell_bitmaps_loaded = 0;
8013 void demo_upsell_show_screens()
8015 int current_time, k;
8018 if ( !Demo_upsell_bitmaps_loaded ) {
8019 demo_upsell_load_bitmaps();
8020 Demo_upsell_bitmaps_loaded = 1;
8023 // may use upsell screens more than once
8024 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8025 Demo_upsell_screen_number = 0;
8032 demo_reset_trailer_timer();
8034 current_time = timer_get_milliseconds();
8041 // don't time out, wait for keypress
8043 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8044 demo_upsell_next_screen();
8049 demo_upsell_next_screen();
8052 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8053 Demo_upsell_screen_number--;
8056 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8061 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8062 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8067 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8077 demo_upsell_unload_bitmaps();
8082 // ----------------------------------------------------------------
8084 // DEMO UPSELL SCREENS END
8086 // ----------------------------------------------------------------
8089 // ----------------------------------------------------------------
8091 // Subspace Ambient Sound START
8093 // ----------------------------------------------------------------
8095 static int Subspace_ambient_left_channel = -1;
8096 static int Subspace_ambient_right_channel = -1;
8099 void game_start_subspace_ambient_sound()
8101 if ( Subspace_ambient_left_channel < 0 ) {
8102 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8105 if ( Subspace_ambient_right_channel < 0 ) {
8106 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8110 void game_stop_subspace_ambient_sound()
8112 if ( Subspace_ambient_left_channel >= 0 ) {
8113 snd_stop(Subspace_ambient_left_channel);
8114 Subspace_ambient_left_channel = -1;
8117 if ( Subspace_ambient_right_channel >= 0 ) {
8118 snd_stop(Subspace_ambient_right_channel);
8119 Subspace_ambient_right_channel = -1;
8123 // ----------------------------------------------------------------
8125 // Subspace Ambient Sound END
8127 // ----------------------------------------------------------------
8129 // ----------------------------------------------------------------
8131 // CDROM detection code START
8133 // ----------------------------------------------------------------
8135 #define CD_SIZE_72_MINUTE_MAX (697000000)
8137 uint game_get_cd_used_space(char *path)
8141 char use_path[512] = "";
8142 char sub_path[512] = "";
8143 WIN32_FIND_DATA find;
8146 // recurse through all files and directories
8147 strcpy(use_path, path);
8148 strcat(use_path, "*.*");
8149 find_handle = FindFirstFile(use_path, &find);
8152 if(find_handle == INVALID_HANDLE_VALUE){
8158 // subdirectory. make sure to ignore . and ..
8159 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8161 strcpy(sub_path, path);
8162 strcat(sub_path, find.cFileName);
8163 strcat(sub_path, "\\");
8164 total += game_get_cd_used_space(sub_path);
8166 total += (uint)find.nFileSizeLow;
8168 } while(FindNextFile(find_handle, &find));
8171 FindClose(find_handle);
8183 // if volume_name is non-null, the CD name must match that
8184 int find_freespace_cd(char *volume_name)
8187 char oldpath[MAX_PATH];
8191 int volume_match = 0;
8195 GetCurrentDirectory(MAX_PATH, oldpath);
8197 for (i = 0; i < 26; i++)
8203 path[0] = (char)('A'+i);
8204 if (GetDriveType(path) == DRIVE_CDROM) {
8206 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8207 nprintf(("CD", "CD volume: %s\n", volume));
8209 // check for any CD volume
8210 int volume1_present = 0;
8211 int volume2_present = 0;
8212 int volume3_present = 0;
8214 char full_check[512] = "";
8216 // look for setup.exe
8217 strcpy(full_check, path);
8218 strcat(full_check, "setup.exe");
8219 find_handle = _findfirst(full_check, &find);
8220 if(find_handle != -1){
8221 volume1_present = 1;
8222 _findclose(find_handle);
8225 // look for intro.mve
8226 strcpy(full_check, path);
8227 strcat(full_check, "intro.mve");
8228 find_handle = _findfirst(full_check, &find);
8229 if(find_handle != -1){
8230 volume2_present = 1;
8231 _findclose(find_handle);
8234 // look for endpart1.mve
8235 strcpy(full_check, path);
8236 strcat(full_check, "endpart1.mve");
8237 find_handle = _findfirst(full_check, &find);
8238 if(find_handle != -1){
8239 volume3_present = 1;
8240 _findclose(find_handle);
8243 // see if we have the specific CD we're looking for
8244 if ( volume_name ) {
8246 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8250 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8254 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8258 if ( volume1_present || volume2_present || volume3_present ) {
8263 // 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
8264 if ( volume_match ){
8266 // 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
8267 if(volume2_present || volume3_present) {
8268 // first step - check to make sure its a cdrom
8269 if(GetDriveType(path) != DRIVE_CDROM){
8273 #if !defined(OEM_BUILD)
8274 // oem not on 80 min cds, so dont check tha size
8276 uint used_space = game_get_cd_used_space(path);
8277 if(used_space < CD_SIZE_72_MINUTE_MAX){
8280 #endif // !defined(OEM_BUILD)
8288 #endif // RELEASE_REAL
8294 SetCurrentDirectory(oldpath);
8303 int set_cdrom_path(int drive_num)
8307 if (drive_num < 0) { //no CD
8309 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8312 strcpy(Game_CDROM_dir,""); //set directory
8316 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8332 i = find_freespace_cd();
8334 rval = set_cdrom_path(i);
8338 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8340 nprintf(("CD", "FreeSpace CD not found\n"));
8348 int Last_cd_label_found = 0;
8349 char Last_cd_label[256];
8351 int game_cd_changed()
8358 if ( strlen(Game_CDROM_dir) == 0 ) {
8362 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8364 if ( found != Last_cd_label_found ) {
8365 Last_cd_label_found = found;
8367 mprintf(( "CD '%s' was inserted\n", label ));
8370 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8374 if ( Last_cd_label_found ) {
8375 if ( !stricmp( Last_cd_label, label )) {
8376 //mprintf(( "CD didn't change\n" ));
8378 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8382 // none found before, none found now.
8383 //mprintf(( "still no CD...\n" ));
8387 Last_cd_label_found = found;
8389 strcpy( Last_cd_label, label );
8391 strcpy( Last_cd_label, "" );
8402 // check if _any_ FreeSpace2 CDs are in the drive
8403 // return: 1 => CD now in drive
8404 // 0 => Could not find CD, they refuse to put it in the drive
8405 int game_do_cd_check(char *volume_name)
8407 #if !defined(GAME_CD_CHECK)
8413 int num_attempts = 0;
8414 int refresh_files = 0;
8416 int path_set_ok, popup_rval;
8418 cd_drive_num = find_freespace_cd(volume_name);
8419 path_set_ok = set_cdrom_path(cd_drive_num);
8420 if ( path_set_ok ) {
8422 if ( refresh_files ) {
8434 // no CD found, so prompt user
8435 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8437 if ( popup_rval != 1 ) {
8442 if ( num_attempts++ > 5 ) {
8453 // check if _any_ FreeSpace2 CDs are in the drive
8454 // return: 1 => CD now in drive
8455 // 0 => Could not find CD, they refuse to put it in the drive
8456 int game_do_cd_check_specific(char *volume_name, int cdnum)
8461 int num_attempts = 0;
8462 int refresh_files = 0;
8464 int path_set_ok, popup_rval;
8466 cd_drive_num = find_freespace_cd(volume_name);
8467 path_set_ok = set_cdrom_path(cd_drive_num);
8468 if ( path_set_ok ) {
8470 if ( refresh_files ) {
8481 // no CD found, so prompt user
8482 #if defined(DVD_MESSAGE_HACK)
8483 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8485 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8488 if ( popup_rval != 1 ) {
8493 if ( num_attempts++ > 5 ) {
8503 // only need to do this in RELEASE_REAL
8504 int game_do_cd_mission_check(char *filename)
8510 fs_builtin_mission *m = game_find_builtin_mission(filename);
8512 // check for changed CD
8513 if(game_cd_changed()){
8518 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8522 // not builtin, so do a general check (any FS2 CD will do)
8524 return game_do_cd_check();
8527 // does not have any CD requirement, do a general check
8528 if(strlen(m->cd_volume) <= 0){
8529 return game_do_cd_check();
8533 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8535 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8537 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8540 return game_do_cd_check();
8543 // did we find the cd?
8544 if(find_freespace_cd(m->cd_volume) >= 0){
8548 // make sure the volume exists
8549 int num_attempts = 0;
8550 int refresh_files = 0;
8552 int path_set_ok, popup_rval;
8554 cd_drive_num = find_freespace_cd(m->cd_volume);
8555 path_set_ok = set_cdrom_path(cd_drive_num);
8556 if ( path_set_ok ) {
8558 if ( refresh_files ) {
8565 // no CD found, so prompt user
8566 #if defined(DVD_MESSAGE_HACK)
8567 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8569 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8573 if ( popup_rval != 1 ) {
8578 if ( num_attempts++ > 5 ) {
8590 // ----------------------------------------------------------------
8592 // CDROM detection code END
8594 // ----------------------------------------------------------------
8596 // ----------------------------------------------------------------
8597 // SHIPS TBL VERIFICATION STUFF
8600 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8601 #define NUM_SHIPS_TBL_CHECKSUMS 1
8604 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8605 1696074201, // FS2 demo
8609 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8610 -463907578, // US - beta 1
8611 1696074201, // FS2 demo
8614 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8615 // -1022810006, // 1.0 FULL
8616 -1254285366 // 1.2 FULL (German)
8620 void verify_ships_tbl()
8624 Game_ships_tbl_valid = 1;
8630 // detect if the packfile exists
8631 CFILE *detect = cfopen("ships.tbl", "rb");
8632 Game_ships_tbl_valid = 0;
8636 Game_ships_tbl_valid = 0;
8640 // get the long checksum of the file
8642 cfseek(detect, 0, SEEK_SET);
8643 cf_chksum_long(detect, &file_checksum);
8647 // now compare the checksum/filesize against known #'s
8648 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8649 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8650 Game_ships_tbl_valid = 1;
8657 DCF(shipspew, "display the checksum for the current ships.tbl")
8660 CFILE *detect = cfopen("ships.tbl", "rb");
8661 // get the long checksum of the file
8663 cfseek(detect, 0, SEEK_SET);
8664 cf_chksum_long(detect, &file_checksum);
8667 dc_printf("%d", file_checksum);
8670 // ----------------------------------------------------------------
8671 // WEAPONS TBL VERIFICATION STUFF
8674 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8675 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8678 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8679 -266420030, // demo 1
8683 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8684 141718090, // US - beta 1
8685 -266420030, // demo 1
8688 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8689 // 399297860, // 1.0 FULL
8690 -553984927 // 1.2 FULL (german)
8694 void verify_weapons_tbl()
8698 Game_weapons_tbl_valid = 1;
8704 // detect if the packfile exists
8705 CFILE *detect = cfopen("weapons.tbl", "rb");
8706 Game_weapons_tbl_valid = 0;
8710 Game_weapons_tbl_valid = 0;
8714 // get the long checksum of the file
8716 cfseek(detect, 0, SEEK_SET);
8717 cf_chksum_long(detect, &file_checksum);
8721 // now compare the checksum/filesize against known #'s
8722 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8723 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8724 Game_weapons_tbl_valid = 1;
8731 DCF(wepspew, "display the checksum for the current weapons.tbl")
8734 CFILE *detect = cfopen("weapons.tbl", "rb");
8735 // get the long checksum of the file
8737 cfseek(detect, 0, SEEK_SET);
8738 cf_chksum_long(detect, &file_checksum);
8741 dc_printf("%d", file_checksum);
8744 // if the game is running using hacked data
8745 int game_hacked_data()
8748 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8756 void display_title_screen()
8758 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8759 ///int title_bitmap;
8762 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8763 if (title_bitmap == -1) {
8769 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8770 extern void d3d_start_frame();
8776 gr_set_bitmap(title_bitmap);
8783 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8784 extern void d3d_stop_frame();
8792 bm_unload(title_bitmap);
8793 #endif // FS2_DEMO || OEM_BUILD
8796 // return true if the game is running with "low memory", which is less than 48MB
8797 bool game_using_low_mem()
8799 if (Use_low_mem == 0) {