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.22 2002/08/02 23:07:03 relnev
19 * don't access the mouse in standalone mode
21 * Revision 1.21 2002/07/28 05:05:08 relnev
22 * removed some old stuff
24 * Revision 1.20 2002/07/24 00:20:41 relnev
27 * Revision 1.19 2002/06/17 06:33:08 relnev
28 * ryan's struct patch for gcc 2.95
30 * Revision 1.18 2002/06/16 04:46:33 relnev
31 * set up correct checksums for demo
33 * Revision 1.17 2002/06/09 04:41:17 relnev
34 * added copyright header
36 * Revision 1.16 2002/06/09 03:16:04 relnev
39 * removed unneeded asm, old sdl 2d setup.
41 * fixed crash caused by opengl_get_region.
43 * Revision 1.15 2002/06/05 08:05:28 relnev
44 * stub/warning removal.
46 * reworked the sound code.
48 * Revision 1.14 2002/06/05 04:03:32 relnev
49 * finished cfilesystem.
51 * removed some old code.
53 * fixed mouse save off-by-one.
57 * Revision 1.13 2002/06/02 04:26:34 relnev
60 * Revision 1.12 2002/06/02 00:31:35 relnev
61 * implemented osregistry
63 * Revision 1.11 2002/06/01 09:00:34 relnev
64 * silly debug memmanager
66 * Revision 1.10 2002/06/01 07:12:32 relnev
67 * a few NDEBUG updates.
69 * removed a few warnings.
71 * Revision 1.9 2002/05/31 03:05:59 relnev
74 * Revision 1.8 2002/05/29 02:52:32 theoddone33
75 * Enable OpenGL renderer
77 * Revision 1.7 2002/05/28 08:52:03 relnev
78 * implemented two assembly stubs.
80 * cleaned up a few warnings.
82 * added a little demo hackery to make it progress a little farther.
84 * Revision 1.6 2002/05/28 06:28:20 theoddone33
85 * Filesystem mods, actually reads some data files now
87 * Revision 1.5 2002/05/28 04:07:28 theoddone33
88 * New graphics stubbing arrangement
90 * Revision 1.4 2002/05/27 22:46:52 theoddone33
91 * Remove more undefined symbols
93 * Revision 1.3 2002/05/26 23:31:18 relnev
94 * added a few files that needed to be compiled
96 * freespace.cpp: now compiles
98 * Revision 1.2 2002/05/07 03:16:44 theoddone33
99 * The Great Newline Fix
101 * Revision 1.1.1.1 2002/05/03 03:28:09 root
105 * 201 6/16/00 3:15p Jefff
106 * sim of the year dvd version changes, a few german soty localization
109 * 200 11/03/99 11:06a Jefff
112 * 199 10/26/99 5:07p Jamest
113 * fixed jeffs dumb debug code
115 * 198 10/25/99 5:53p Jefff
116 * call control_config_common_init() on startup
118 * 197 10/14/99 10:18a Daveb
119 * Fixed incorrect CD checking problem on standalone server.
121 * 196 10/13/99 9:22a Daveb
122 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
123 * related to movies. Fixed launcher spawning from PXO screen.
125 * 195 10/06/99 11:05a Jefff
126 * new oem upsell 3 hotspot coords
128 * 194 10/06/99 10:31a Jefff
131 * 193 10/01/99 9:10a Daveb
134 * 192 9/15/99 4:57a Dave
135 * Updated ships.tbl checksum
137 * 191 9/15/99 3:58a Dave
138 * Removed framerate warning at all times.
140 * 190 9/15/99 3:16a Dave
141 * Remove mt-011.fs2 from the builtin mission list.
143 * 189 9/15/99 1:45a Dave
144 * Don't init joystick on standalone. Fixed campaign mode on standalone.
145 * Fixed no-score-report problem in TvT
147 * 188 9/14/99 6:08a Dave
148 * Updated (final) single, multi, and campaign list.
150 * 187 9/14/99 3:26a Dave
151 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
152 * respawn-too-early problem. Made a few crash points safe.
154 * 186 9/13/99 4:52p Dave
157 * 185 9/12/99 8:09p Dave
158 * Fixed problem where skip-training button would cause mission messages
159 * not to get paged out for the current mission.
161 * 184 9/10/99 11:53a Dave
162 * Shutdown graphics before sound to eliminate apparent lockups when
163 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
165 * 183 9/09/99 11:40p Dave
166 * Handle an Assert() in beam code. Added supernova sounds. Play the right
167 * 2 end movies properly, based upon what the player did in the mission.
169 * 182 9/08/99 10:29p Dave
170 * Make beam sound pausing and unpausing much safer.
172 * 181 9/08/99 10:01p Dave
173 * Make sure game won't run in a drive's root directory. Make sure
174 * standalone routes suqad war messages properly to the host.
176 * 180 9/08/99 3:22p Dave
177 * Updated builtin mission list.
179 * 179 9/08/99 12:01p Jefff
180 * fixed Game_builtin_mission_list typo on Training-2.fs2
182 * 178 9/08/99 9:48a Andsager
183 * Add force feedback for engine wash.
185 * 177 9/07/99 4:01p Dave
186 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
187 * does everything properly (setting up address when binding). Remove
188 * black rectangle background from UI_INPUTBOX.
190 * 176 9/13/99 2:40a Dave
191 * Comment in full 80 minute CD check for RELEASE_REAL builds.
193 * 175 9/06/99 6:38p Dave
194 * Improved CD detection code.
196 * 174 9/06/99 1:30a Dave
197 * Intermediate checkin. Started on enforcing CD-in-drive to play the
200 * 173 9/06/99 1:16a Dave
201 * Make sure the user sees the intro movie.
203 * 172 9/04/99 8:00p Dave
204 * Fixed up 1024 and 32 bit movie support.
206 * 171 9/03/99 1:32a Dave
207 * CD checking by act. Added support to play 2 cutscenes in a row
208 * seamlessly. Fixed super low level cfile bug related to files in the
209 * root directory of a CD. Added cheat code to set campaign mission # in
212 * 170 9/01/99 10:49p Dave
213 * Added nice SquadWar checkbox to the client join wait screen.
215 * 169 9/01/99 10:14a Dave
218 * 168 8/29/99 4:51p Dave
219 * Fixed damaged checkin.
221 * 167 8/29/99 4:18p Andsager
222 * New "burst" limit for friendly damage. Also credit more damage done
223 * against large friendly ships.
225 * 166 8/27/99 6:38p Alanl
226 * crush the blasted repeating messages bug
228 * 164 8/26/99 9:09p Dave
229 * Force framerate check in everything but a RELEASE_REAL build.
231 * 163 8/26/99 9:45a Dave
232 * First pass at easter eggs and cheats.
234 * 162 8/24/99 8:55p Dave
235 * Make sure nondimming pixels work properly in tech menu.
237 * 161 8/24/99 1:49a Dave
238 * Fixed client-side afterburner stuttering. Added checkbox for no version
239 * checking on PXO join. Made button info passing more friendly between
242 * 160 8/22/99 5:53p Dave
243 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
244 * instead of ship designations for multiplayer players.
246 * 159 8/22/99 1:19p Dave
247 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
248 * which d3d cards are detected.
250 * 158 8/20/99 2:09p Dave
251 * PXO banner cycling.
253 * 157 8/19/99 10:59a Dave
254 * Packet loss detection.
256 * 156 8/19/99 10:12a Alanl
257 * preload mission-specific messages on machines greater than 48MB
259 * 155 8/16/99 4:04p Dave
260 * Big honking checkin.
262 * 154 8/11/99 5:54p Dave
263 * Fixed collision problem. Fixed standalone ghost problem.
265 * 153 8/10/99 7:59p Jefff
268 * 152 8/10/99 6:54p Dave
269 * Mad optimizations. Added paging to the nebula effect.
271 * 151 8/10/99 3:44p Jefff
272 * loads Intelligence information on startup
274 * 150 8/09/99 3:47p Dave
275 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
276 * non-nebula missions.
278 * 149 8/09/99 2:21p Andsager
279 * Fix patching from multiplayer direct to launcher update tab.
281 * 148 8/09/99 10:36a Dave
282 * Version info for game.
284 * 147 8/06/99 9:46p Dave
285 * Hopefully final changes for the demo.
287 * 146 8/06/99 3:34p Andsager
288 * Make title version info "(D)" -> "D" show up nicely
290 * 145 8/06/99 2:59p Adamp
291 * Fixed NT launcher/update problem.
293 * 144 8/06/99 1:52p Dave
294 * Bumped up MAX_BITMAPS for the demo.
296 * 143 8/06/99 12:17p Andsager
297 * Demo: down to just 1 demo dog
299 * 142 8/05/99 9:39p Dave
300 * Yet another new checksum.
302 * 141 8/05/99 6:19p Dave
303 * New demo checksums.
305 * 140 8/05/99 5:31p Andsager
306 * Up demo version 1.01
308 * 139 8/05/99 4:22p Andsager
309 * No time limit on upsell screens. Reverse order of display of upsell
312 * 138 8/05/99 4:17p Dave
313 * Tweaks to client interpolation.
315 * 137 8/05/99 3:52p Danw
317 * 136 8/05/99 3:01p Danw
319 * 135 8/05/99 2:43a Anoop
320 * removed duplicate definition.
322 * 134 8/05/99 2:13a Dave
325 * 133 8/05/99 2:05a Dave
328 * 132 8/05/99 1:22a Andsager
331 * 131 8/04/99 9:51p Andsager
332 * Add title screen to demo
334 * 130 8/04/99 6:47p Jefff
335 * fixed link error resulting from #ifdefs
337 * 129 8/04/99 6:26p Dave
338 * Updated ship tbl checksum.
340 * 128 8/04/99 5:40p Andsager
341 * Add multiple demo dogs
343 * 127 8/04/99 5:36p Andsager
344 * Show upsell screens at end of demo campaign before returning to main
347 * 126 8/04/99 11:42a Danw
348 * tone down EAX reverb
350 * 125 8/04/99 11:23a Dave
351 * Updated demo checksums.
353 * 124 8/03/99 11:02p Dave
354 * Maybe fixed sync problems in multiplayer.
356 * 123 8/03/99 6:21p Jefff
359 * 122 8/03/99 3:44p Andsager
360 * Launch laucher if trying to run FS without first having configured
363 * 121 8/03/99 12:45p Dave
366 * 120 8/02/99 9:13p Dave
369 * 119 7/30/99 10:31p Dave
370 * Added comm menu to the configurable hud files.
372 * 118 7/30/99 5:17p Andsager
373 * first fs2demo checksums
375 * 117 7/29/99 3:09p Anoop
377 * 116 7/29/99 12:05a Dave
378 * Nebula speed optimizations.
380 * 115 7/27/99 8:59a Andsager
381 * Make major, minor version consistent for all builds. Only show major
382 * and minor for launcher update window.
384 * 114 7/26/99 5:50p Dave
385 * Revised ingame join. Better? We'll see....
387 * 113 7/26/99 5:27p Andsager
388 * Add training mission as builtin to demo build
390 * 112 7/24/99 1:54p Dave
391 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
394 * 111 7/22/99 4:00p Dave
395 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
397 * 110 7/21/99 8:10p Dave
398 * First run of supernova effect.
400 * 109 7/20/99 1:49p Dave
401 * Peter Drake build. Fixed some release build warnings.
403 * 108 7/19/99 2:26p Andsager
404 * set demo multiplayer missions
406 * 107 7/18/99 5:19p Dave
407 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
409 * 106 7/16/99 1:50p Dave
410 * 8 bit aabitmaps. yay.
412 * 105 7/15/99 3:07p Dave
413 * 32 bit detection support. Mouse coord commandline.
415 * 104 7/15/99 2:13p Dave
416 * Added 32 bit detection.
418 * 103 7/15/99 9:20a Andsager
419 * FS2_DEMO initial checkin
421 * 102 7/14/99 11:02a Dave
422 * Skill level default back to easy. Blech.
424 * 101 7/09/99 5:54p Dave
425 * Seperated cruiser types into individual types. Added tons of new
426 * briefing icons. Campaign screen.
428 * 100 7/08/99 4:43p Andsager
429 * New check for sparky_hi and print if not found.
431 * 99 7/08/99 10:53a Dave
432 * New multiplayer interpolation scheme. Not 100% done yet, but still
433 * better than the old way.
435 * 98 7/06/99 4:24p Dave
436 * Mid-level checkin. Starting on some potentially cool multiplayer
439 * 97 7/06/99 3:35p Andsager
440 * Allow movie to play before red alert mission.
442 * 96 7/03/99 5:50p Dave
443 * Make rotated bitmaps draw properly in padlock views.
445 * 95 7/02/99 9:55p Dave
446 * Player engine wash sound.
448 * 94 7/02/99 4:30p Dave
449 * Much more sophisticated lightning support.
451 * 93 6/29/99 7:52p Dave
452 * Put in exception handling in FS2.
454 * 92 6/22/99 9:37p Dave
455 * Put in pof spewing.
457 * 91 6/16/99 4:06p Dave
458 * New pilot info popup. Added new draw-bitmap-as-poly function.
460 * 90 6/15/99 1:56p Andsager
461 * For release builds, allow start up in high res only with
464 * 89 6/15/99 9:34a Dave
465 * Fixed key checking in single threaded version of the stamp notification
468 * 88 6/09/99 2:55p Andsager
469 * Allow multiple asteroid subtypes (of large, medium, small) and follow
472 * 87 6/08/99 1:14a Dave
473 * Multi colored hud test.
475 * 86 6/04/99 9:52a Dave
476 * Fixed some rendering problems.
478 * 85 6/03/99 10:15p Dave
479 * Put in temporary main hall screen.
481 * 84 6/02/99 6:18p Dave
482 * Fixed TNT lockup problems! Wheeeee!
484 * 83 6/01/99 3:52p Dave
485 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
486 * dead popup, pxo find player popup, pxo private room popup.
488 * 82 5/26/99 1:28p Jasenw
489 * changed coords for loading ani
491 * 81 5/26/99 11:46a Dave
492 * Added ship-blasting lighting and made the randomization of lighting
493 * much more customizable.
495 * 80 5/24/99 5:45p Dave
496 * Added detail levels to the nebula, with a decent speedup. Split nebula
497 * lightning into its own section.
515 #include "systemvars.h"
520 #include "starfield.h"
521 #include "lighting.h"
526 #include "fireballs.h"
530 #include "floating.h"
531 #include "gamesequence.h"
533 #include "optionsmenu.h"
534 #include "playermenu.h"
535 #include "trainingmenu.h"
536 #include "techmenu.h"
539 #include "hudmessage.h"
541 #include "missiongoals.h"
542 #include "missionparse.h"
547 #include "multiutil.h"
548 #include "multimsgs.h"
552 #include "freespace.h"
553 #include "managepilot.h"
555 #include "contexthelp.h"
558 #include "missionbrief.h"
559 #include "missiondebrief.h"
561 #include "missionshipchoice.h"
563 #include "hudconfig.h"
564 #include "controlsconfig.h"
565 #include "missionmessage.h"
566 #include "missiontraining.h"
568 #include "hudtarget.h"
570 #include "eventmusic.h"
571 #include "animplay.h"
572 #include "missionweaponchoice.h"
573 #include "missionlog.h"
574 #include "audiostr.h"
576 #include "missioncampaign.h"
578 #include "missionhotkey.h"
579 #include "objectsnd.h"
580 #include "cmeasure.h"
582 #include "linklist.h"
583 #include "shockwave.h"
584 #include "afterburner.h"
589 #include "stand_gui.h"
590 #include "pcxutils.h"
591 #include "hudtargetbox.h"
592 #include "multi_xfer.h"
593 #include "hudescort.h"
594 #include "multiutil.h"
597 #include "multiteamselect.h"
600 #include "readyroom.h"
601 #include "mainhallmenu.h"
602 #include "multilag.h"
604 #include "particle.h"
606 #include "multi_ingame.h"
607 #include "snazzyui.h"
608 #include "asteroid.h"
609 #include "popupdead.h"
610 #include "multi_voice.h"
611 #include "missioncmdbrief.h"
612 #include "redalert.h"
613 #include "gameplayhelp.h"
614 #include "multilag.h"
615 #include "staticrand.h"
616 #include "multi_pmsg.h"
617 #include "levelpaging.h"
618 #include "observer.h"
619 #include "multi_pause.h"
620 #include "multi_endgame.h"
621 #include "cutscenes.h"
622 #include "multi_respawn.h"
624 #include "multi_obj.h"
625 #include "multi_log.h"
627 #include "localize.h"
628 #include "osregistry.h"
629 #include "barracks.h"
630 #include "missionpause.h"
632 #include "alphacolors.h"
633 #include "objcollide.h"
636 #include "neblightning.h"
637 #include "shipcontrails.h"
640 #include "multi_dogfight.h"
641 #include "multi_rate.h"
642 #include "muzzleflash.h"
646 #include "mainhalltemp.h"
647 #include "exceptionhandler.h"
651 #include "supernova.h"
652 #include "hudshield.h"
653 // #include "names.h"
655 #include "missionloopbrief.h"
659 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
665 // 1.00.04 5/26/98 MWA -- going final (12 pm)
666 // 1.00.03 5/26/98 MWA -- going final (3 am)
667 // 1.00.02 5/25/98 MWA -- going final
668 // 1.00.01 5/25/98 MWA -- going final
669 // 0.90 5/21/98 MWA -- getting ready for final.
670 // 0.10 4/9/98. Set by MK.
672 // Demo version: (obsolete since DEMO codebase split from tree)
673 // 0.03 4/10/98 AL. Interplay rev
674 // 0.02 4/8/98 MK. Increased when this system was modified.
675 // 0.01 4/7/98? AL. First release to Interplay QA.
678 // 1.00 5/28/98 AL. First release to Interplay QA.
680 void game_level_init(int seed = -1);
681 void game_post_level_init();
682 void game_do_frame();
683 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
684 void game_reset_time();
685 void game_show_framerate(); // draws framerate in lower right corner
687 int Game_no_clear = 0;
689 int Pofview_running = 0;
690 int Nebedit_running = 0;
692 typedef struct big_expl_flash {
693 float max_flash_intensity; // max intensity
694 float cur_flash_intensity; // cur intensity
695 int flash_start; // start time
698 #define FRAME_FILTER 16
700 #define DEFAULT_SKILL_LEVEL 1
701 int Game_skill_level = DEFAULT_SKILL_LEVEL;
703 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
704 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
706 #define EXE_FNAME ("fs2.exe")
707 #define LAUNCHER_FNAME ("freespace2.exe")
709 // JAS: Code for warphole camera.
710 // Needs to be cleaned up.
711 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
712 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
713 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
714 matrix Camera_orient = IDENTITY_MATRIX;
715 float Camera_damping = 1.0f;
716 float Camera_time = 0.0f;
717 float Warpout_time = 0.0f;
718 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
719 int Warpout_sound = -1;
721 int Use_joy_mouse = 0;
722 int Use_palette_flash = 1;
724 int Use_fullscreen_at_startup = 0;
726 int Show_area_effect = 0;
727 object *Last_view_target = NULL;
729 int dogfight_blown = 0;
732 float frametimes[FRAME_FILTER];
733 float frametotal = 0.0f;
737 int Show_framerate = 0;
739 int Show_framerate = 1;
742 int Framerate_cap = 120;
745 int Show_target_debug_info = 0;
746 int Show_target_weapons = 0;
750 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
753 int Debug_octant = -1;
755 fix Game_time_compression = F1_0;
757 // if the ships.tbl the player has is valid
758 int Game_ships_tbl_valid = 0;
760 // if the weapons.tbl the player has is valid
761 int Game_weapons_tbl_valid = 0;
765 extern int Player_attacking_enabled;
769 int Pre_player_entry;
771 int Fred_running = 0;
772 char Game_current_mission_filename[MAX_FILENAME_LEN];
773 int game_single_step = 0;
774 int last_single_step=0;
776 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
777 extern int MSG_WINDOW_Y_START;
778 extern int MSG_WINDOW_HEIGHT;
780 int game_zbuffer = 1;
781 //static int Game_music_paused;
782 static int Game_paused;
786 #define EXPIRE_BAD_CHECKSUM 1
787 #define EXPIRE_BAD_TIME 2
789 extern void ssm_init();
790 extern void ssm_level_init();
791 extern void ssm_process();
793 // static variable to contain the time this version was built
794 // commented out for now until
795 // I figure out how to get the username into the file
796 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
798 // defines and variables used for dumping frame for making trailers.
800 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
801 int Debug_dump_trigger = 0;
802 int Debug_dump_frame_count;
803 int Debug_dump_frame_num = 0;
804 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
807 // amount of time to wait after the player has died before we display the death died popup
808 #define PLAYER_DIED_POPUP_WAIT 2500
809 int Player_died_popup_wait = -1;
810 int Player_multi_died_check = -1;
812 // builtin mission list stuff
814 int Game_builtin_mission_count = 6;
815 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
816 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
817 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
818 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
819 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
820 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
821 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
823 #elif defined(PD_BUILD)
824 int Game_builtin_mission_count = 4;
825 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
826 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
827 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
828 { "sm1-01", (FSB_FROM_VOLITION), "" },
829 { "sm1-05", (FSB_FROM_VOLITION), "" },
831 #elif defined(MULTIPLAYER_BETA)
832 int Game_builtin_mission_count = 17;
833 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
835 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
838 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
841 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
845 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
846 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
847 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
848 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
849 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
850 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
851 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
853 #elif defined(OEM_BUILD)
854 int Game_builtin_mission_count = 17;
855 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
856 // oem version - act 1 only
857 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
860 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
861 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
862 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
863 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
866 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
869 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
870 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
871 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
872 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
873 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
874 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
875 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
878 int Game_builtin_mission_count = 92;
879 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
880 // single player campaign
881 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
884 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
885 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
886 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
887 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
896 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
899 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
900 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
901 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
902 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
905 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
906 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
907 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
908 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
909 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
911 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
912 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
922 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
925 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
926 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
927 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
928 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
930 // multiplayer missions
933 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
939 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
987 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
988 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
989 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
990 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
995 // Internal function prototypes
996 void game_maybe_draw_mouse(float frametime);
997 void init_animating_pointer();
998 void load_animating_pointer(char *filename, int dx, int dy);
999 void unload_animating_pointer();
1000 void game_do_training_checks();
1001 void game_shutdown(void);
1002 void game_show_event_debug(float frametime);
1003 void game_event_debug_init();
1005 void demo_upsell_show_screens();
1006 void game_start_subspace_ambient_sound();
1007 void game_stop_subspace_ambient_sound();
1008 void verify_ships_tbl();
1009 void verify_weapons_tbl();
1010 void display_title_screen();
1012 // loading background filenames
1013 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1014 "LoadingBG", // GR_640
1015 "2_LoadingBG" // GR_1024
1019 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1020 "Loading.ani", // GR_640
1021 "2_Loading.ani" // GR_1024
1024 #if defined(FS2_DEMO)
1025 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1029 #elif defined(OEM_BUILD)
1030 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1037 char Game_CDROM_dir[MAX_PATH_LEN];
1040 // How much RAM is on this machine. Set in WinMain
1041 uint Freespace_total_ram = 0;
1044 float Game_flash_red = 0.0f;
1045 float Game_flash_green = 0.0f;
1046 float Game_flash_blue = 0.0f;
1047 float Sun_spot = 0.0f;
1048 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1050 // game shudder stuff (in ms)
1051 int Game_shudder_time = -1;
1052 int Game_shudder_total = 0;
1053 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1056 sound_env Game_sound_env;
1057 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1058 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1060 int Game_sound_env_update_timestamp;
1062 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1065 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1067 fs_builtin_mission *game_find_builtin_mission(char *filename)
1071 // look through all existing builtin missions
1072 for(idx=0; idx<Game_builtin_mission_count; idx++){
1073 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1074 return &Game_builtin_mission_list[idx];
1082 int game_get_default_skill_level()
1084 return DEFAULT_SKILL_LEVEL;
1088 void game_flash_reset()
1090 Game_flash_red = 0.0f;
1091 Game_flash_green = 0.0f;
1092 Game_flash_blue = 0.0f;
1094 Big_expl_flash.max_flash_intensity = 0.0f;
1095 Big_expl_flash.cur_flash_intensity = 0.0f;
1096 Big_expl_flash.flash_start = 0;
1099 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1100 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1102 void game_framerate_check_init()
1104 // zero critical time
1105 Gf_critical_time = 0.0f;
1108 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1109 // if this is a glide card
1110 if(gr_screen.mode == GR_GLIDE){
1112 extern GrHwConfiguration hwconfig;
1115 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1116 Gf_critical = 15.0f;
1120 Gf_critical = 10.0f;
1125 Gf_critical = 15.0f;
1128 // d3d. only care about good cards here I guess (TNT)
1130 Gf_critical = 15.0f;
1133 // if this is a glide card
1134 if(gr_screen.mode == GR_GLIDE){
1136 extern GrHwConfiguration hwconfig;
1139 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1140 Gf_critical = 25.0f;
1144 Gf_critical = 20.0f;
1149 Gf_critical = 25.0f;
1152 // d3d. only care about good cards here I guess (TNT)
1154 Gf_critical = 25.0f;
1159 extern float Framerate;
1160 void game_framerate_check()
1164 // if the current framerate is above the critical level, add frametime
1165 if(Framerate >= Gf_critical){
1166 Gf_critical_time += flFrametime;
1169 if(!Show_framerate){
1173 // display if we're above the critical framerate
1174 if(Framerate < Gf_critical){
1175 gr_set_color_fast(&Color_bright_red);
1176 gr_string(200, y_start, "Framerate warning");
1181 // display our current pct of good frametime
1182 if(f2fl(Missiontime) >= 0.0f){
1183 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1186 gr_set_color_fast(&Color_bright_green);
1188 gr_set_color_fast(&Color_bright_red);
1191 gr_printf(200, y_start, "%d%%", (int)pct);
1198 // Adds a flash effect. These can be positive or negative.
1199 // The range will get capped at around -1 to 1, so stick
1200 // with a range like that.
1201 void game_flash( float r, float g, float b )
1203 Game_flash_red += r;
1204 Game_flash_green += g;
1205 Game_flash_blue += b;
1207 if ( Game_flash_red < -1.0f ) {
1208 Game_flash_red = -1.0f;
1209 } else if ( Game_flash_red > 1.0f ) {
1210 Game_flash_red = 1.0f;
1213 if ( Game_flash_green < -1.0f ) {
1214 Game_flash_green = -1.0f;
1215 } else if ( Game_flash_green > 1.0f ) {
1216 Game_flash_green = 1.0f;
1219 if ( Game_flash_blue < -1.0f ) {
1220 Game_flash_blue = -1.0f;
1221 } else if ( Game_flash_blue > 1.0f ) {
1222 Game_flash_blue = 1.0f;
1227 // Adds a flash for Big Ship explosions
1228 // cap range from 0 to 1
1229 void big_explosion_flash(float flash)
1231 Big_expl_flash.flash_start = timestamp(1);
1235 } else if (flash < 0.0f) {
1239 Big_expl_flash.max_flash_intensity = flash;
1240 Big_expl_flash.cur_flash_intensity = 0.0f;
1243 // Amount to diminish palette towards normal, per second.
1244 #define DIMINISH_RATE 0.75f
1245 #define SUN_DIMINISH_RATE 6.00f
1249 float sn_glare_scale = 1.7f;
1252 dc_get_arg(ARG_FLOAT);
1253 sn_glare_scale = Dc_arg_float;
1256 float Supernova_last_glare = 0.0f;
1257 void game_sunspot_process(float frametime)
1261 float Sun_spot_goal = 0.0f;
1264 sn_stage = supernova_active();
1266 // sunspot differently based on supernova stage
1268 // approaching. player still in control
1271 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1274 light_get_global_dir(&light_dir, 0);
1276 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1279 // scale it some more
1280 dot = dot * (0.5f + (pct * 0.5f));
1283 Sun_spot_goal += (dot * sn_glare_scale);
1286 // draw the sun glow
1287 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1288 // draw the glow for this sun
1289 stars_draw_sun_glow(0);
1292 Supernova_last_glare = Sun_spot_goal;
1295 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1298 Sun_spot_goal = 0.9f;
1299 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1301 if(Sun_spot_goal > 1.0f){
1302 Sun_spot_goal = 1.0f;
1305 Sun_spot_goal *= sn_glare_scale;
1306 Supernova_last_glare = Sun_spot_goal;
1309 // fade to white. display dead popup
1312 Supernova_last_glare += (2.0f * flFrametime);
1313 if(Supernova_last_glare > 2.0f){
1314 Supernova_last_glare = 2.0f;
1317 Sun_spot_goal = Supernova_last_glare;
1324 // check sunspots for all suns
1325 n_lights = light_get_global_count();
1328 for(idx=0; idx<n_lights; idx++){
1329 //(vector *eye_pos, matrix *eye_orient)
1330 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1333 light_get_global_dir(&light_dir, idx);
1335 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1337 Sun_spot_goal += (float)pow(dot,85.0f);
1339 // draw the glow for this sun
1340 stars_draw_sun_glow(idx);
1342 Sun_spot_goal = 0.0f;
1348 Sun_spot_goal = 0.0f;
1352 float dec_amount = frametime*SUN_DIMINISH_RATE;
1354 if ( Sun_spot < Sun_spot_goal ) {
1355 Sun_spot += dec_amount;
1356 if ( Sun_spot > Sun_spot_goal ) {
1357 Sun_spot = Sun_spot_goal;
1359 } else if ( Sun_spot > Sun_spot_goal ) {
1360 Sun_spot -= dec_amount;
1361 if ( Sun_spot < Sun_spot_goal ) {
1362 Sun_spot = Sun_spot_goal;
1368 // Call once a frame to diminish the
1369 // flash effect to 0.
1370 void game_flash_diminish(float frametime)
1372 float dec_amount = frametime*DIMINISH_RATE;
1374 if ( Game_flash_red > 0.0f ) {
1375 Game_flash_red -= dec_amount;
1376 if ( Game_flash_red < 0.0f )
1377 Game_flash_red = 0.0f;
1379 Game_flash_red += dec_amount;
1380 if ( Game_flash_red > 0.0f )
1381 Game_flash_red = 0.0f;
1384 if ( Game_flash_green > 0.0f ) {
1385 Game_flash_green -= dec_amount;
1386 if ( Game_flash_green < 0.0f )
1387 Game_flash_green = 0.0f;
1389 Game_flash_green += dec_amount;
1390 if ( Game_flash_green > 0.0f )
1391 Game_flash_green = 0.0f;
1394 if ( Game_flash_blue > 0.0f ) {
1395 Game_flash_blue -= dec_amount;
1396 if ( Game_flash_blue < 0.0f )
1397 Game_flash_blue = 0.0f;
1399 Game_flash_blue += dec_amount;
1400 if ( Game_flash_blue > 0.0f )
1401 Game_flash_blue = 0.0f;
1404 // update big_explosion_cur_flash
1405 #define TIME_UP 1500
1406 #define TIME_DOWN 2500
1407 int duration = TIME_UP + TIME_DOWN;
1408 int time = timestamp_until(Big_expl_flash.flash_start);
1409 if (time > -duration) {
1411 if (time < TIME_UP) {
1412 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1415 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1419 if ( Use_palette_flash ) {
1421 // static int or=0, og=0, ob=0;
1423 // Change the 200 to change the color range of colors.
1424 r = fl2i( Game_flash_red*128.0f );
1425 g = fl2i( Game_flash_green*128.0f );
1426 b = fl2i( Game_flash_blue*128.0f );
1428 if ( Sun_spot > 0.0f ) {
1429 r += fl2i(Sun_spot*128.0f);
1430 g += fl2i(Sun_spot*128.0f);
1431 b += fl2i(Sun_spot*128.0f);
1434 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1435 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1436 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1437 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1440 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1441 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1442 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1444 if ( (r!=0) || (g!=0) || (b!=0) ) {
1445 gr_flash( r, g, b );
1447 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1458 void game_level_close()
1460 // De-Initialize the game subsystems
1461 message_mission_shutdown();
1462 event_music_level_close();
1463 game_stop_looped_sounds();
1465 obj_snd_level_close(); // uninit object-linked persistant sounds
1466 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1467 anim_level_close(); // stop and clean up any anim instances
1468 shockwave_level_close();
1469 fireball_level_close();
1471 mission_event_shutdown();
1472 asteroid_level_close();
1473 model_cache_reset(); // Reset/free all the model caching stuff
1474 flak_level_close(); // unload flak stuff
1475 neb2_level_close(); // shutdown gaseous nebula stuff
1478 mflash_level_close();
1480 audiostream_unpause_all();
1485 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1486 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1487 void game_level_init(int seed)
1489 // seed the random number generator
1491 // if no seed was passed, seed the generator either from the time value, or from the
1492 // netgame security flags -- ensures that all players in multiplayer game will have the
1493 // same randon number sequence (with static rand functions)
1494 if ( Game_mode & GM_NORMAL ) {
1495 Game_level_seed = time(NULL);
1497 Game_level_seed = Netgame.security;
1500 // mwa 9/17/98 -- maybe this assert isn't needed????
1501 Assert( !(Game_mode & GM_MULTIPLAYER) );
1502 Game_level_seed = seed;
1504 srand( Game_level_seed );
1506 // semirand function needs to get re-initted every time in multiplayer
1507 if ( Game_mode & GM_MULTIPLAYER ){
1513 Key_normal_game = (Game_mode & GM_NORMAL);
1516 Game_shudder_time = -1;
1518 // Initialize the game subsystems
1519 // timestamp_reset(); // Must be inited before everything else
1521 game_reset_time(); // resets time, and resets saved time too
1523 obj_init(); // Must be inited before the other systems
1524 model_free_all(); // Free all existing models
1525 mission_brief_common_init(); // Free all existing briefing/debriefing text
1526 weapon_level_init();
1527 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1529 player_level_init();
1530 shipfx_flash_init(); // Init the ship gun flash system.
1531 game_flash_reset(); // Reset the flash effect
1532 particle_init(); // Reset the particle system
1536 shield_hit_init(); // Initialize system for showing shield hits
1537 radar_mission_init();
1538 mission_init_goals();
1541 obj_snd_level_init(); // init object-linked persistant sounds
1543 shockwave_level_init();
1544 afterburner_level_init();
1545 scoring_level_init( &Player->stats );
1547 asteroid_level_init();
1548 control_config_clear_used_status();
1549 collide_ship_ship_sounds_init();
1551 Pre_player_entry = 1; // Means the player has not yet entered.
1552 Entry_delay_time = 0; // Could get overwritten in mission read.
1553 fireball_preload(); // page in warphole bitmaps
1555 flak_level_init(); // initialize flak - bitmaps, etc
1556 ct_level_init(); // initialize ships contrails, etc
1557 awacs_level_init(); // initialize AWACS
1558 beam_level_init(); // initialize beam weapons
1559 mflash_level_init();
1561 supernova_level_init();
1563 // multiplayer dogfight hack
1566 shipfx_engine_wash_level_init();
1570 Last_view_target = NULL;
1575 // campaign wasn't ended
1576 Campaign_ended_in_mission = 0;
1579 // called when a mission is over -- does server specific stuff.
1580 void freespace_stop_mission()
1583 Game_mode &= ~GM_IN_MISSION;
1586 // called at frame interval to process networking stuff
1587 void game_do_networking()
1589 Assert( Net_player != NULL );
1590 if (!(Game_mode & GM_MULTIPLAYER)){
1594 // see if this player should be reading/writing data. Bit is set when at join
1595 // screen onward until quits back to main menu.
1596 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1600 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1603 multi_pause_do_frame();
1608 // Loads the best palette for this level, based
1609 // on nebula color and hud color. You could just call palette_load_table with
1610 // the appropriate filename, but who wants to do that.
1611 void game_load_palette()
1613 char palette_filename[1024];
1615 // We only use 3 hud colors right now
1616 // Assert( HUD_config.color >= 0 );
1617 // Assert( HUD_config.color <= 2 );
1619 Assert( Mission_palette >= 0 );
1620 Assert( Mission_palette <= 98 );
1622 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1623 strcpy( palette_filename, NOX("gamepalette-subspace") );
1625 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1628 mprintf(( "Loading palette %s\n", palette_filename ));
1630 // palette_load_table(palette_filename);
1633 void game_post_level_init()
1635 // Stuff which gets called after mission is loaded. Because player isn't created until
1636 // after mission loads, some things must get initted after the level loads
1638 model_level_post_init();
1641 hud_setup_escort_list();
1642 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1648 game_event_debug_init();
1651 training_mission_init();
1652 asteroid_create_all();
1654 game_framerate_check_init();
1658 // An estimate as to how high the count passed to game_loading_callback will go.
1659 // This is just a guess, it seems to always be about the same. The count is
1660 // proportional to the code being executed, not the time, so this works good
1661 // for a bar, assuming the code does about the same thing each time you
1662 // load a level. You can find this value by looking at the return value
1663 // of game_busy_callback(NULL), which I conveniently print out to the
1664 // debug output window with the '=== ENDING LOAD ==' stuff.
1665 //#define COUNT_ESTIMATE 3706
1666 #define COUNT_ESTIMATE 1111
1668 int Game_loading_callback_inited = 0;
1670 int Game_loading_background = -1;
1671 anim * Game_loading_ani = NULL;
1672 anim_instance *Game_loading_ani_instance;
1673 int Game_loading_frame=-1;
1675 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1684 // This gets called 10x per second and count is the number of times
1685 // game_busy() has been called since the current callback function
1687 void game_loading_callback(int count)
1689 game_do_networking();
1691 Assert( Game_loading_callback_inited==1 );
1692 Assert( Game_loading_ani != NULL );
1694 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1695 if ( framenum > Game_loading_ani->total_frames-1 ) {
1696 framenum = Game_loading_ani->total_frames-1;
1697 } else if ( framenum < 0 ) {
1702 while ( Game_loading_frame < framenum ) {
1703 Game_loading_frame++;
1704 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1708 if ( cbitmap > -1 ) {
1709 if ( Game_loading_background > -1 ) {
1710 gr_set_bitmap( Game_loading_background );
1714 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1715 gr_set_bitmap( cbitmap );
1716 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1718 bm_release(cbitmap);
1724 void game_loading_callback_init()
1726 Assert( Game_loading_callback_inited==0 );
1728 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1729 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1732 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1733 Assert( Game_loading_ani != NULL );
1734 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1735 Assert( Game_loading_ani_instance != NULL );
1736 Game_loading_frame = -1;
1738 Game_loading_callback_inited = 1;
1740 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1745 void game_loading_callback_close()
1747 Assert( Game_loading_callback_inited==1 );
1749 // Make sure bar shows all the way over.
1750 game_loading_callback(COUNT_ESTIMATE);
1752 int real_count = game_busy_callback( NULL );
1755 Game_loading_callback_inited = 0;
1758 mprintf(( "=================== ENDING LOAD ================\n" ));
1759 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1760 mprintf(( "================================================\n" ));
1762 // to remove warnings in release build
1766 free_anim_instance(Game_loading_ani_instance);
1767 Game_loading_ani_instance = NULL;
1768 anim_free(Game_loading_ani);
1769 Game_loading_ani = NULL;
1771 bm_release( Game_loading_background );
1772 common_free_interface_palette(); // restore game palette
1773 Game_loading_background = -1;
1775 gr_set_font( FONT1 );
1778 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1780 void game_maybe_update_sound_environment()
1782 // do nothing for now
1785 // Assign the sound environment for the game, based on the current mission
1787 void game_assign_sound_environment()
1790 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1791 Game_sound_env.id = SND_ENV_DRUGGED;
1792 Game_sound_env.volume = 0.800f;
1793 Game_sound_env.damping = 1.188f;
1794 Game_sound_env.decay = 6.392f;
1796 } else if (Num_asteroids > 30) {
1797 Game_sound_env.id = SND_ENV_AUDITORIUM;
1798 Game_sound_env.volume = 0.603f;
1799 Game_sound_env.damping = 0.5f;
1800 Game_sound_env.decay = 4.279f;
1803 Game_sound_env = Game_default_sound_env;
1807 Game_sound_env = Game_default_sound_env;
1808 Game_sound_env_update_timestamp = timestamp(1);
1811 // function which gets called before actually entering the mission. It is broken down into a funciton
1812 // since it will get called in one place from a single player game and from another place for
1813 // a multiplayer game
1814 void freespace_mission_load_stuff()
1816 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1817 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1818 if(!(Game_mode & GM_STANDALONE_SERVER)){
1820 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1822 game_loading_callback_init();
1824 event_music_level_init(); // preloads the first 2 seconds for each event music track
1827 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1830 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1833 ship_assign_sound_all(); // assign engine sounds to ships
1834 game_assign_sound_environment(); // assign the sound environment for this mission
1837 // call function in missionparse.cpp to fixup player/ai stuff.
1838 mission_parse_fixup_players();
1841 // Load in all the bitmaps for this level
1846 game_loading_callback_close();
1848 // the only thing we need to call on the standalone for now.
1850 // call function in missionparse.cpp to fixup player/ai stuff.
1851 mission_parse_fixup_players();
1853 // Load in all the bitmaps for this level
1859 uint load_mission_load;
1860 uint load_post_level_init;
1861 uint load_mission_stuff;
1863 // tells the server to load the mission and initialize structures
1864 int game_start_mission()
1866 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1868 load_gl_init = time(NULL);
1870 load_gl_init = time(NULL) - load_gl_init;
1872 if (Game_mode & GM_MULTIPLAYER) {
1873 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1875 // clear multiplayer stats
1876 init_multiplayer_stats();
1879 load_mission_load = time(NULL);
1880 if (mission_load()) {
1881 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1882 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1883 gameseq_post_event(GS_EVENT_MAIN_MENU);
1885 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1890 load_mission_load = time(NULL) - load_mission_load;
1892 // If this is a red alert mission in campaign mode, bash wingman status
1893 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1894 red_alert_bash_wingman_status();
1897 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1898 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1899 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1900 // game_load_palette();
1903 load_post_level_init = time(NULL);
1904 game_post_level_init();
1905 load_post_level_init = time(NULL) - load_post_level_init;
1909 void Do_model_timings_test();
1910 Do_model_timings_test();
1914 load_mission_stuff = time(NULL);
1915 freespace_mission_load_stuff();
1916 load_mission_stuff = time(NULL) - load_mission_stuff;
1921 int Interface_framerate = 0;
1924 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1925 DCF_BOOL( show_framerate, Show_framerate )
1926 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1927 DCF_BOOL( show_target_weapons, Show_target_weapons )
1928 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1929 DCF_BOOL( sound, Sound_enabled )
1930 DCF_BOOL( zbuffer, game_zbuffer )
1931 DCF_BOOL( shield_system, New_shield_system )
1932 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1933 DCF_BOOL( player_attacking, Player_attacking_enabled )
1934 DCF_BOOL( show_waypoints, Show_waypoints )
1935 DCF_BOOL( show_area_effect, Show_area_effect )
1936 DCF_BOOL( show_net_stats, Show_net_stats )
1937 DCF_BOOL( log, Log_debug_output_to_file )
1938 DCF_BOOL( training_msg_method, Training_msg_method )
1939 DCF_BOOL( show_player_pos, Show_player_pos )
1940 DCF_BOOL(i_framerate, Interface_framerate )
1942 DCF(show_mem,"Toggles showing mem usage")
1945 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1946 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1947 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1948 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1954 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1956 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1957 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1961 DCF(show_cpu,"Toggles showing cpu usage")
1964 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1965 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1966 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1967 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1973 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1975 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1976 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1983 // AL 4-8-98: always allow players to display their framerate
1986 DCF_BOOL( show_framerate, Show_framerate )
1993 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1996 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1997 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1998 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1999 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2001 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" );
2002 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2004 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2007 DCF(palette_flash,"Toggles palette flash effect on/off")
2010 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2011 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2012 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2013 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2015 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2016 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2019 int Use_low_mem = 0;
2021 DCF(low_mem,"Uses low memory settings regardless of RAM")
2024 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2025 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2026 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2027 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2029 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2030 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2032 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2038 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2041 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2042 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2043 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2044 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2046 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2047 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2048 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2052 int Framerate_delay = 0;
2054 float Freespace_gamma = 1.0f;
2056 DCF(gamma,"Sets Gamma factor")
2059 dc_get_arg(ARG_FLOAT|ARG_NONE);
2060 if ( Dc_arg_type & ARG_FLOAT ) {
2061 Freespace_gamma = Dc_arg_float;
2063 dc_printf( "Gamma reset to 1.0f\n" );
2064 Freespace_gamma = 1.0f;
2066 if ( Freespace_gamma < 0.1f ) {
2067 Freespace_gamma = 0.1f;
2068 } else if ( Freespace_gamma > 5.0f ) {
2069 Freespace_gamma = 5.0f;
2071 gr_set_gamma(Freespace_gamma);
2073 char tmp_gamma_string[32];
2074 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2075 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2079 dc_printf( "Usage: gamma <float>\n" );
2080 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2081 Dc_status = 0; // don't print status if help is printed. Too messy.
2085 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2094 Game_current_mission_filename[0] = 0;
2096 // seed the random number generator
2097 Game_init_seed = time(NULL);
2098 srand( Game_init_seed );
2100 Framerate_delay = 0;
2106 extern void bm_init();
2112 // Initialize the timer before the os
2120 GetCurrentDirectory(1024, whee);
2123 getcwd (whee, 1024);
2126 strcat(whee, EXE_FNAME);
2128 //Initialize the libraries
2129 s1 = timer_get_milliseconds();
2130 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2133 e1 = timer_get_milliseconds();
2135 // time a bunch of cfopens
2137 s2 = timer_get_milliseconds();
2139 for(int idx=0; idx<10000; idx++){
2140 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2145 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2147 e2 = timer_get_milliseconds();
2150 if (Is_standalone) {
2151 std_init_standalone();
2153 os_init( Osreg_class_name, Osreg_app_name );
2154 os_set_title(Osreg_title);
2157 // initialize localization module. Make sure this is down AFTER initialzing OS.
2158 // int t1 = timer_get_milliseconds();
2161 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2163 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2166 // verify that he has a valid weapons.tbl
2167 verify_weapons_tbl();
2169 // Output version numbers to registry for auto patching purposes
2170 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2171 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2172 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2174 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2175 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2176 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2179 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2183 Asteroids_enabled = 1;
2186 /////////////////////////////
2188 /////////////////////////////
2193 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2194 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2196 if (!stricmp(ptr, NOX("no sound"))) {
2197 Cmdline_freespace_no_sound = 1;
2199 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2201 } else if (!stricmp(ptr, NOX("EAX"))) {
2206 if (!Is_standalone) {
2207 snd_init(use_a3d, use_eax);
2209 /////////////////////////////
2211 /////////////////////////////
2213 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2216 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);
2218 // fire up the UpdateLauncher executable
2220 PROCESS_INFORMATION pi;
2222 memset( &si, 0, sizeof(STARTUPINFO) );
2225 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2226 NULL, // pointer to command line string
2227 NULL, // pointer to process security attributes
2228 NULL, // pointer to thread security attributes
2229 FALSE, // handle inheritance flag
2230 CREATE_DEFAULT_ERROR_MODE, // creation flags
2231 NULL, // pointer to new environment block
2232 NULL, // pointer to current directory name
2233 &si, // pointer to STARTUPINFO
2234 &pi // pointer to PROCESS_INFORMATION
2237 // If the Launcher could not be started up, let the user know
2239 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2248 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2250 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);
2258 // check for hi res pack file
2259 int has_sparky_hi = 0;
2261 // check if sparky_hi exists -- access mode 0 means does file exist
2264 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2267 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2270 // see if we've got 32 bit in the string
2271 if(strstr(ptr, "32 bit")){
2278 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2280 // always 640 for E3
2281 gr_init(GR_640, GR_GLIDE);
2283 // regular or hi-res ?
2285 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2287 if(strstr(ptr, NOX("(1024x768)"))){
2289 gr_init(GR_1024, GR_GLIDE);
2291 gr_init(GR_640, GR_GLIDE);
2294 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2296 // always 640 for E3
2298 gr_init(GR_640, GR_DIRECT3D, depth);
2300 // regular or hi-res ?
2302 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2304 if(strstr(ptr, NOX("(1024x768)"))){
2308 gr_init(GR_1024, GR_DIRECT3D, depth);
2312 gr_init(GR_640, GR_DIRECT3D, depth);
2318 if ( Use_fullscreen_at_startup && !Is_standalone) {
2319 gr_init(GR_640, GR_DIRECTDRAW);
2321 gr_init(GR_640, GR_SOFTWARE);
2324 if ( !Is_standalone ) {
2325 gr_init(GR_640, GR_DIRECTDRAW);
2327 gr_init(GR_640, GR_SOFTWARE);
2332 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2333 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2334 gr_init(GR_1024, GR_OPENGL);
2336 gr_init(GR_640, GR_OPENGL);
2340 gr_init(GR_640, GR_SOFTWARE);
2345 extern int Gr_inited;
2346 if(trying_d3d && !Gr_inited){
2348 extern char Device_init_error[512];
2349 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2358 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2359 Freespace_gamma = (float)atof(ptr);
2360 if ( Freespace_gamma == 0.0f ) {
2361 Freespace_gamma = 1.80f;
2362 } else if ( Freespace_gamma < 0.1f ) {
2363 Freespace_gamma = 0.1f;
2364 } else if ( Freespace_gamma > 5.0f ) {
2365 Freespace_gamma = 5.0f;
2367 char tmp_gamma_string[32];
2368 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2369 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2371 gr_set_gamma(Freespace_gamma);
2373 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2376 display_title_screen();
2380 // attempt to load up master tracker registry info (login and password)
2381 Multi_tracker_id = -1;
2383 // pxo login and password
2384 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2386 nprintf(("Network","Error reading in PXO login data\n"));
2387 strcpy(Multi_tracker_login,"");
2389 strcpy(Multi_tracker_login,ptr);
2391 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2393 nprintf(("Network","Error reading PXO password\n"));
2394 strcpy(Multi_tracker_passwd,"");
2396 strcpy(Multi_tracker_passwd,ptr);
2399 // pxo squad name and password
2400 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2402 nprintf(("Network","Error reading in PXO squad name\n"));
2403 strcpy(Multi_tracker_squad_name, "");
2405 strcpy(Multi_tracker_squad_name, ptr);
2408 // If less than 48MB of RAM, use low memory model.
2411 (Freespace_total_ram < 48*1024*1024) ||
2414 mprintf(( "Using normal memory settings...\n" ));
2415 bm_set_low_mem(1); // Use every other frame of bitmaps
2417 mprintf(( "Using high memory settings...\n" ));
2418 bm_set_low_mem(0); // Use all frames of bitmaps
2421 // load non-darkening pixel defs
2422 palman_load_pixels();
2424 // hud shield icon stuff
2425 hud_shield_game_init();
2427 control_config_common_init(); // sets up localization stuff in the control config
2433 gamesnd_parse_soundstbl();
2438 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2443 player_controls_init();
2446 //if(!Is_standalone){
2454 ship_init(); // read in ships.tbl
2456 mission_campaign_init(); // load in the default campaign
2458 // navmap_init(); // init the navigation map system
2459 context_help_init();
2460 techroom_intel_init(); // parse species.tbl, load intel info
2462 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2463 init_animating_pointer();
2465 mission_brief_common_init(); // Mark all the briefing structures as empty.
2466 gr_font_init(); // loads up all fonts
2468 neb2_init(); // fullneb stuff
2472 player_tips_init(); // helpful tips
2475 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2476 pilot_load_pic_list();
2477 pilot_load_squad_pic_list();
2479 load_animating_pointer(NOX("cursor"), 0, 0);
2481 // initialize alpha colors
2482 alpha_colors_init();
2485 // Game_music_paused = 0;
2492 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2493 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2495 mprintf(("cfile_init() took %d\n", e1 - s1));
2496 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2499 char transfer_text[128];
2501 float Start_time = 0.0f;
2503 float Framerate = 0.0f;
2505 float Timing_total = 0.0f;
2506 float Timing_render2 = 0.0f;
2507 float Timing_render3 = 0.0f;
2508 float Timing_flip = 0.0f;
2509 float Timing_clear = 0.0f;
2511 MONITOR(NumPolysDrawn);
2517 void game_get_framerate()
2519 char text[128] = "";
2521 if ( frame_int == -1 ) {
2523 for (i=0; i<FRAME_FILTER; i++ ) {
2524 frametimes[i] = 0.0f;
2529 frametotal -= frametimes[frame_int];
2530 frametotal += flFrametime;
2531 frametimes[frame_int] = flFrametime;
2532 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2534 if ( frametotal != 0.0 ) {
2535 if ( Framecount >= FRAME_FILTER )
2536 Framerate = FRAME_FILTER / frametotal;
2538 Framerate = Framecount / frametotal;
2539 sprintf( text, NOX("FPS: %.1f"), Framerate );
2541 sprintf( text, NOX("FPS: ?") );
2545 if (Show_framerate) {
2546 gr_set_color_fast(&HUD_color_debug);
2547 gr_string( 570, 2, text );
2551 void game_show_framerate()
2555 cur_time = f2fl(timer_get_approx_seconds());
2556 if (cur_time - Start_time > 30.0f) {
2557 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2558 Start_time += 1000.0f;
2561 //mprintf(( "%s\n", text ));
2564 if ( Debug_dump_frames )
2568 // possibly show control checking info
2569 control_check_indicate();
2571 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2572 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2573 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2574 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2577 if ( Show_cpu == 1 ) {
2582 dy = gr_get_font_height() + 1;
2584 gr_set_color_fast(&HUD_color_debug);
2588 extern int D3D_textures_in;
2589 extern int D3D_textures_in_frame;
2590 extern int Glide_textures_in;
2591 extern int Glide_textures_in_frame;
2592 extern int Glide_explosion_vram;
2593 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2595 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2597 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2601 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2603 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2605 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2607 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2609 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2614 extern int Num_pairs; // Number of object pairs that were checked.
2615 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2618 extern int Num_pairs_checked; // What percent of object pairs were checked.
2619 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2621 Num_pairs_checked = 0;
2625 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2628 if ( Timing_total > 0.01f ) {
2629 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2631 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2633 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2635 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2637 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2647 dy = gr_get_font_height() + 1;
2649 gr_set_color_fast(&HUD_color_debug);
2652 extern int TotalRam;
2653 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2658 extern int Model_ram;
2659 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2663 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2665 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2667 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2671 extern int D3D_textures_in;
2672 extern int Glide_textures_in;
2673 extern int Glide_textures_in_frame;
2674 extern int Glide_explosion_vram;
2675 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2677 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2679 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2686 if ( Show_player_pos ) {
2690 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));
2693 MONITOR_INC(NumPolys, modelstats_num_polys);
2694 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2695 MONITOR_INC(NumVerts, modelstats_num_verts );
2697 modelstats_num_polys = 0;
2698 modelstats_num_polys_drawn = 0;
2699 modelstats_num_verts = 0;
2700 modelstats_num_sortnorms = 0;
2704 void game_show_standalone_framerate()
2706 float frame_rate=30.0f;
2707 if ( frame_int == -1 ) {
2709 for (i=0; i<FRAME_FILTER; i++ ) {
2710 frametimes[i] = 0.0f;
2715 frametotal -= frametimes[frame_int];
2716 frametotal += flFrametime;
2717 frametimes[frame_int] = flFrametime;
2718 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2720 if ( frametotal != 0.0 ) {
2721 if ( Framecount >= FRAME_FILTER ){
2722 frame_rate = FRAME_FILTER / frametotal;
2724 frame_rate = Framecount / frametotal;
2727 std_set_standalone_fps(frame_rate);
2731 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2732 void game_show_time_left()
2736 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2737 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2738 // checking how much time is left
2740 if ( Mission_end_time == -1 ){
2744 diff = f2i(Mission_end_time - Missiontime);
2745 // be sure to bash to 0. diff could be negative on frame that we quit mission
2750 hud_set_default_color();
2751 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2754 //========================================================================================
2755 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2756 //========================================================================================
2760 DCF(ai_pause,"Pauses ai")
2763 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2764 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2765 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2766 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2769 obj_init_all_ships_physics();
2772 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2773 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2776 DCF(single_step,"Single steps the game")
2779 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2780 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2781 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2782 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2784 last_single_step = 0; // Make so single step waits a frame before stepping
2787 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2788 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2791 DCF_BOOL(physics_pause, physics_paused)
2792 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2793 DCF_BOOL(ai_firing, Ai_firing_enabled )
2795 // Create some simple aliases to these commands...
2796 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2797 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2798 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2799 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2800 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2803 //========================================================================================
2804 //========================================================================================
2807 void game_training_pause_do()
2811 key = game_check_key();
2813 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2820 void game_increase_skill_level()
2823 if (Game_skill_level >= NUM_SKILL_LEVELS){
2824 Game_skill_level = 0;
2828 int Player_died_time;
2830 int View_percent = 100;
2833 DCF(view, "Sets the percent of the 3d view to render.")
2836 dc_get_arg(ARG_INT);
2837 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2838 View_percent = Dc_arg_int;
2840 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2846 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2850 dc_printf("View is set to %d%%\n", View_percent );
2855 // Set the clip region for the 3d rendering window
2856 void game_set_view_clip()
2858 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2859 // Set the clip region for the letterbox "dead view"
2860 int yborder = gr_screen.max_h/4;
2862 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2863 // J.S. I've changed my ways!! See the new "no constants" code!!!
2864 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2866 // Set the clip region for normal view
2867 if ( View_percent >= 100 ) {
2870 int xborder, yborder;
2872 if ( View_percent < 5 ) {
2876 float fp = i2fl(View_percent)/100.0f;
2877 int fi = fl2i(fl_sqrt(fp)*100.0f);
2878 if ( fi > 100 ) fi=100;
2880 xborder = ( gr_screen.max_w*(100-fi) )/200;
2881 yborder = ( gr_screen.max_h*(100-fi) )/200;
2883 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2889 void show_debug_stuff()
2892 int laser_count = 0, missile_count = 0;
2894 for (i=0; i<MAX_OBJECTS; i++) {
2895 if (Objects[i].type == OBJ_WEAPON){
2896 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2898 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2904 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2907 extern int Tool_enabled;
2912 int tst_bitmap = -1;
2914 float tst_offset, tst_offset_total;
2917 void game_tst_frame_pre()
2925 g3_rotate_vertex(&v, &tst_pos);
2926 g3_project_vertex(&v);
2929 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2933 // big ship? always tst
2935 // within 3000 meters
2936 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2940 // within 300 meters
2941 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2948 void game_tst_frame()
2958 tst_time = time(NULL);
2960 // load the tst bitmap
2961 switch((int)frand_range(0.0f, 3.0)){
2963 tst_bitmap = bm_load("ig_jim");
2965 mprintf(("TST 0\n"));
2969 tst_bitmap = bm_load("ig_kan");
2971 mprintf(("TST 1\n"));
2975 tst_bitmap = bm_load("ig_jim");
2977 mprintf(("TST 2\n"));
2981 tst_bitmap = bm_load("ig_kan");
2983 mprintf(("TST 3\n"));
2992 // get the tst bitmap dimensions
2994 bm_get_info(tst_bitmap, &w, &h);
2997 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2999 snd_play(&Snds[SND_VASUDAN_BUP]);
3001 // tst x and direction
3005 tst_offset_total = (float)w;
3006 tst_offset = (float)w;
3008 tst_x = (float)gr_screen.max_w;
3009 tst_offset_total = (float)-w;
3010 tst_offset = (float)w;
3018 float diff = (tst_offset_total / 0.5f) * flFrametime;
3024 tst_offset -= fl_abs(diff);
3025 } else if(tst_mode == 2){
3028 tst_offset -= fl_abs(diff);
3032 gr_set_bitmap(tst_bitmap);
3033 gr_bitmap((int)tst_x, (int)tst_y);
3036 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3040 // if we passed the switch point
3041 if(tst_offset <= 0.0f){
3046 tst_stamp = timestamp(1000);
3047 tst_offset = fl_abs(tst_offset_total);
3058 void game_tst_mark(object *objp, ship *shipp)
3067 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3070 sip = &Ship_info[shipp->ship_info_index];
3077 tst_pos = objp->pos;
3078 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3084 extern void render_shields();
3086 void player_repair_frame(float frametime)
3088 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3090 for(idx=0;idx<MAX_PLAYERS;idx++){
3093 np = &Net_players[idx];
3095 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)){
3097 // don't rearm/repair if the player is dead or dying/departing
3098 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3099 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3104 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3105 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3111 #define NUM_FRAMES_TEST 300
3112 #define NUM_MIXED_SOUNDS 16
3113 void do_timing_test(float flFrametime)
3115 static int framecount = 0;
3116 static int test_running = 0;
3117 static float test_time = 0.0f;
3119 static int snds[NUM_MIXED_SOUNDS];
3122 if ( test_running ) {
3124 test_time += flFrametime;
3125 if ( framecount >= NUM_FRAMES_TEST ) {
3127 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3128 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3133 if ( Test_begin == 1 ) {
3139 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3142 // start looping digital sounds
3143 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3144 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3151 DCF(dcf_fov, "Change the field of view")
3154 dc_get_arg(ARG_FLOAT|ARG_NONE);
3155 if ( Dc_arg_type & ARG_NONE ) {
3156 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3157 dc_printf( "Zoom factor reset\n" );
3159 if ( Dc_arg_type & ARG_FLOAT ) {
3160 if (Dc_arg_float < 0.25f) {
3161 Viewer_zoom = 0.25f;
3162 dc_printf("Zoom factor pinned at 0.25.\n");
3163 } else if (Dc_arg_float > 1.25f) {
3164 Viewer_zoom = 1.25f;
3165 dc_printf("Zoom factor pinned at 1.25.\n");
3167 Viewer_zoom = Dc_arg_float;
3173 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3176 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3180 DCF(framerate_cap, "Sets the framerate cap")
3183 dc_get_arg(ARG_INT);
3184 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3185 Framerate_cap = Dc_arg_int;
3187 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3193 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3194 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3195 dc_printf("[n] must be from 1 to 120.\n");
3199 if ( Framerate_cap )
3200 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3202 dc_printf("There is no framerate cap currently active.\n");
3206 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3207 int Show_viewing_from_self = 0;
3209 void say_view_target()
3211 object *view_target;
3213 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3214 view_target = &Objects[Player_ai->target_objnum];
3216 view_target = Player_obj;
3218 if (Game_mode & GM_DEAD) {
3219 if (Player_ai->target_objnum != -1)
3220 view_target = &Objects[Player_ai->target_objnum];
3223 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3224 if (view_target != Player_obj){
3226 char *view_target_name = NULL;
3227 switch(Objects[Player_ai->target_objnum].type) {
3229 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3232 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3233 Viewer_mode &= ~VM_OTHER_SHIP;
3235 case OBJ_JUMP_NODE: {
3236 char jump_node_name[128];
3237 strcpy(jump_node_name, XSTR( "jump node", 184));
3238 view_target_name = jump_node_name;
3239 Viewer_mode &= ~VM_OTHER_SHIP;
3248 if ( view_target_name ) {
3249 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3250 Show_viewing_from_self = 1;
3253 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3254 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3255 Show_viewing_from_self = 1;
3257 if (Show_viewing_from_self)
3258 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3263 Last_view_target = view_target;
3267 float Game_hit_x = 0.0f;
3268 float Game_hit_y = 0.0f;
3270 // Reset at the beginning of each frame
3271 void game_whack_reset()
3277 // Apply a 2d whack to the player
3278 void game_whack_apply( float x, float y )
3280 // Do some force feedback
3281 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3287 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3290 // call to apply a "shudder"
3291 void game_shudder_apply(int time, float intensity)
3293 Game_shudder_time = timestamp(time);
3294 Game_shudder_total = time;
3295 Game_shudder_intensity = intensity;
3298 #define FF_SCALE 10000
3299 void apply_hud_shake(matrix *eye_orient)
3301 if (Viewer_obj == Player_obj) {
3302 physics_info *pi = &Player_obj->phys_info;
3310 // Make eye shake due to afterburner
3311 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3314 dtime = timestamp_until(pi->afterburner_decay);
3318 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3319 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3322 // Make eye shake due to engine wash
3324 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3327 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3328 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3330 // get the intensity
3331 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3335 vm_vec_rand_vec_quick(&rand_vec);
3338 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3342 // make hud shake due to shuddering
3343 if(Game_shudder_time != -1){
3344 // if the timestamp has elapsed
3345 if(timestamp_elapsed(Game_shudder_time)){
3346 Game_shudder_time = -1;
3348 // otherwise apply some shudder
3352 dtime = timestamp_until(Game_shudder_time);
3356 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));
3357 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));
3362 vm_angles_2_matrix(&tm, &tangles);
3363 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3364 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3365 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3366 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3371 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3373 // Player's velocity just before he blew up. Used to keep camera target moving.
3374 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3376 // Set eye_pos and eye_orient based on view mode.
3377 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3381 static int last_Viewer_mode = 0;
3382 static int last_Game_mode = 0;
3383 static int last_Viewer_objnum = -1;
3385 // This code is supposed to detect camera "cuts"... like going between
3388 // determine if we need to regenerate the nebula
3389 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3390 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3391 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3392 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3393 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3394 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3395 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3396 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3397 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3400 // regenerate the nebula
3404 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3405 //mprintf(( "************** Camera cut! ************\n" ));
3406 last_Viewer_mode = Viewer_mode;
3407 last_Game_mode = Game_mode;
3409 // Camera moved. Tell stars & debris to not do blurring.
3415 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3416 player_display_packlock_view();
3419 game_set_view_clip();
3421 if (Game_mode & GM_DEAD) {
3422 vector vec_to_deader, view_pos;
3425 Viewer_mode |= VM_DEAD_VIEW;
3427 if (Player_ai->target_objnum != -1) {
3428 int view_from_player = 1;
3430 if (Viewer_mode & VM_OTHER_SHIP) {
3431 // View from target.
3432 Viewer_obj = &Objects[Player_ai->target_objnum];
3434 last_Viewer_objnum = Player_ai->target_objnum;
3436 if ( Viewer_obj->type == OBJ_SHIP ) {
3437 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3438 view_from_player = 0;
3441 last_Viewer_objnum = -1;
3444 if ( view_from_player ) {
3445 // View target from player ship.
3447 *eye_pos = Player_obj->pos;
3448 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3449 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3452 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3454 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3455 dist += flFrametime * 16.0f;
3457 vm_vec_scale(&vec_to_deader, -dist);
3458 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3460 view_pos = Player_obj->pos;
3462 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3463 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3464 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3465 Dead_player_last_vel = Player_obj->phys_info.vel;
3466 //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));
3467 } else if (Player_ai->target_objnum != -1) {
3468 view_pos = Objects[Player_ai->target_objnum].pos;
3470 // Make camera follow explosion, but gradually slow down.
3471 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3472 view_pos = Player_obj->pos;
3473 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3474 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3477 *eye_pos = Dead_camera_pos;
3479 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3481 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3486 // if supernova shockwave
3487 if(supernova_camera_cut()){
3491 // call it dead view
3492 Viewer_mode |= VM_DEAD_VIEW;
3494 // set eye pos and orient
3495 supernova_set_view(eye_pos, eye_orient);
3497 // If already blown up, these other modes can override.
3498 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3499 Viewer_mode &= ~VM_DEAD_VIEW;
3501 Viewer_obj = Player_obj;
3503 if (Viewer_mode & VM_OTHER_SHIP) {
3504 if (Player_ai->target_objnum != -1){
3505 Viewer_obj = &Objects[Player_ai->target_objnum];
3506 last_Viewer_objnum = Player_ai->target_objnum;
3508 Viewer_mode &= ~VM_OTHER_SHIP;
3509 last_Viewer_objnum = -1;
3512 last_Viewer_objnum = -1;
3515 if (Viewer_mode & VM_EXTERNAL) {
3518 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3519 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3521 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3523 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3524 vm_vec_normalize(&eye_dir);
3525 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3528 // Modify the orientation based on head orientation.
3529 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3531 } else if ( Viewer_mode & VM_CHASE ) {
3534 if ( Viewer_obj->phys_info.speed < 0.1 )
3535 move_dir = Viewer_obj->orient.v.fvec;
3537 move_dir = Viewer_obj->phys_info.vel;
3538 vm_vec_normalize(&move_dir);
3541 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3542 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3543 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3544 vm_vec_normalize(&eye_dir);
3546 // JAS: I added the following code because if you slew up using
3547 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3548 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3549 // call because the up and the forward vector are the same. I fixed
3550 // it by adding in a fraction of the right vector all the time to the
3552 vector tmp_up = Viewer_obj->orient.v.uvec;
3553 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3555 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3558 // Modify the orientation based on head orientation.
3559 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3560 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3561 *eye_pos = Camera_pos;
3563 ship * shipp = &Ships[Player_obj->instance];
3565 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3566 vm_vec_normalize(&eye_dir);
3567 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3570 // get an eye position based upon the correct type of object
3571 switch(Viewer_obj->type){
3573 // make a call to get the eye point for the player object
3574 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3577 // make a call to get the eye point for the player object
3578 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3584 #ifdef JOHNS_DEBUG_CODE
3585 john_debug_stuff(&eye_pos, &eye_orient);
3591 apply_hud_shake(eye_orient);
3593 // setup neb2 rendering
3594 neb2_render_setup(eye_pos, eye_orient);
3598 extern void ai_debug_render_stuff();
3601 int Game_subspace_effect = 0;
3602 DCF_BOOL( subspace, Game_subspace_effect );
3604 // Does everything needed to render a frame
3605 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3609 g3_start_frame(game_zbuffer);
3610 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3612 // maybe offset the HUD (jitter stuff)
3613 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3614 HUD_set_offsets(Viewer_obj, !dont_offset);
3616 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3617 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3618 // must be done before ships are rendered
3619 if ( MULTIPLAYER_CLIENT ) {
3620 shield_point_multi_setup();
3623 if ( Game_subspace_effect ) {
3624 stars_draw(0,0,0,1);
3626 stars_draw(1,1,1,0);
3629 obj_render_all(obj_render);
3630 beam_render_all(); // render all beam weapons
3631 particle_render_all(); // render particles after everything else.
3632 trail_render_all(); // render missilie trails after everything else.
3633 mflash_render_all(); // render all muzzle flashes
3635 // Why do we not show the shield effect in these modes? Seems ok.
3636 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3640 // render nebula lightning
3643 // render local player nebula
3644 neb2_render_player();
3647 ai_debug_render_stuff();
3650 #ifndef RELEASE_REAL
3651 // game_framerate_check();
3655 extern void snd_spew_debug_info();
3656 snd_spew_debug_info();
3659 //================ END OF 3D RENDERING STUFF ====================
3663 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3664 hud_maybe_clear_head_area();
3665 anim_render_all(0, flFrametime);
3668 extern int Multi_display_netinfo;
3669 if(Multi_display_netinfo){
3670 extern void multi_display_netinfo();
3671 multi_display_netinfo();
3674 game_tst_frame_pre();
3677 do_timing_test(flFrametime);
3681 extern int OO_update_index;
3682 multi_rate_display(OO_update_index, 375, 0);
3687 extern void oo_display();
3694 //#define JOHNS_DEBUG_CODE 1
3696 #ifdef JOHNS_DEBUG_CODE
3697 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3699 //if ( keyd_pressed[KEY_LSHIFT] )
3701 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3703 model_subsystem *turret = tsys->system_info;
3705 if (turret->type == SUBSYSTEM_TURRET ) {
3706 vector v.fvec, v.uvec;
3707 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3709 ship_model_start(tobj);
3711 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3712 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3713 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3715 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3717 ship_model_stop(tobj);
3727 // following function for dumping frames for purposes of building trailers.
3730 // function to toggle state of dumping every frame into PCX when playing the game
3731 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3735 if ( Debug_dump_frames == 0 ) {
3737 Debug_dump_frames = 15;
3738 Debug_dump_trigger = 0;
3739 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3740 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3743 Debug_dump_frames = 0;
3744 Debug_dump_trigger = 0;
3745 gr_dump_frame_stop();
3746 dc_printf( "Frame dumping is now OFF\n" );
3752 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3756 if ( Debug_dump_frames == 0 ) {
3758 Debug_dump_frames = 15;
3759 Debug_dump_trigger = 1;
3760 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3761 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3764 Debug_dump_frames = 0;
3765 Debug_dump_trigger = 0;
3766 gr_dump_frame_stop();
3767 dc_printf( "Frame dumping is now OFF\n" );
3773 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3777 if ( Debug_dump_frames == 0 ) {
3779 Debug_dump_frames = 30;
3780 Debug_dump_trigger = 0;
3781 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3782 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3785 Debug_dump_frames = 0;
3786 Debug_dump_trigger = 0;
3787 gr_dump_frame_stop();
3788 dc_printf( "Frame dumping is now OFF\n" );
3794 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3798 if ( Debug_dump_frames == 0 ) {
3800 Debug_dump_frames = 30;
3801 Debug_dump_trigger = 1;
3802 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3803 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3806 Debug_dump_frames = 0;
3807 Debug_dump_trigger = 0;
3808 gr_dump_frame_stop();
3809 dc_printf( "Triggered frame dumping is now OFF\n" );
3815 void game_maybe_dump_frame()
3817 if ( !Debug_dump_frames ){
3821 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3828 Debug_dump_frame_num++;
3834 extern int Player_dead_state;
3836 // Flip the page and time how long it took.
3837 void game_flip_page_and_time_it()
3841 t1 = timer_get_fixed_seconds();
3843 t2 = timer_get_fixed_seconds();
3845 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3846 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3849 void game_simulation_frame()
3851 // blow ships up in multiplayer dogfight
3852 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){
3853 // blow up all non-player ships
3854 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3857 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3859 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)){
3860 moveup = GET_NEXT(moveup);
3863 shipp = &Ships[Objects[moveup->objnum].instance];
3864 sip = &Ship_info[shipp->ship_info_index];
3866 // only blow up small ships
3867 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3868 // function to simply explode a ship where it is currently at
3869 ship_self_destruct( &Objects[moveup->objnum] );
3872 moveup = GET_NEXT(moveup);
3878 // process AWACS stuff - do this first thing
3881 // single player, set Player hits_this_frame to 0
3882 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3883 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3884 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3888 supernova_process();
3889 if(supernova_active() >= 5){
3893 // fire targeting lasers now so that
3894 // 1 - created this frame
3895 // 2 - collide this frame
3896 // 3 - render this frame
3897 // 4 - ignored and deleted next frame
3898 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3900 ship_process_targeting_lasers();
3902 // do this here so that it works for multiplayer
3904 // get viewer direction
3905 int viewer_direction = PHYSICS_VIEWER_REAR;
3907 if(Viewer_mode == 0){
3908 viewer_direction = PHYSICS_VIEWER_FRONT;
3910 if(Viewer_mode & VM_PADLOCK_UP){
3911 viewer_direction = PHYSICS_VIEWER_UP;
3913 else if(Viewer_mode & VM_PADLOCK_REAR){
3914 viewer_direction = PHYSICS_VIEWER_REAR;
3916 else if(Viewer_mode & VM_PADLOCK_LEFT){
3917 viewer_direction = PHYSICS_VIEWER_LEFT;
3919 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3920 viewer_direction = PHYSICS_VIEWER_RIGHT;
3923 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3925 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3928 #define VM_PADLOCK_UP (1 << 7)
3929 #define VM_PADLOCK_REAR (1 << 8)
3930 #define VM_PADLOCK_LEFT (1 << 9)
3931 #define VM_PADLOCK_RIGHT (1 << 10)
3933 // evaluate mission departures and arrivals before we process all objects.
3934 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3936 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3937 // ships/wing packets.
3938 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3939 mission_parse_eval_stuff();
3942 // if we're an observer, move ourselves seperately from the standard physics
3943 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3944 obj_observer_move(flFrametime);
3947 // move all the objects now
3948 obj_move_all(flFrametime);
3950 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3951 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3952 // ship_check_cargo_all();
3953 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3954 mission_eval_goals();
3958 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3959 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3960 training_check_objectives();
3963 // do all interpolation now
3964 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3965 // client side processing of warping in effect stages
3966 multi_do_client_warp(flFrametime);
3968 // client side movement of an observer
3969 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3970 obj_observer_move(flFrametime);
3973 // move all objects - does interpolation now as well
3974 obj_move_all(flFrametime);
3977 // only process the message queue when the player is "in" the game
3978 if ( !Pre_player_entry ){
3979 message_queue_process(); // process any messages send to the player
3982 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3983 message_maybe_distort(); // maybe distort incoming message if comms damaged
3984 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3985 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3986 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3989 if(!(Game_mode & GM_STANDALONE_SERVER)){
3990 // process some stuff every frame (before frame is rendered)
3991 emp_process_local();
3993 hud_update_frame(); // update hud systems
3995 if (!physics_paused) {
3996 // Move particle system
3997 particle_move_all(flFrametime);
3999 // Move missile trails
4000 trail_move_all(flFrametime);
4002 // process muzzle flashes
4003 mflash_process_all();
4005 // Flash the gun flashes
4006 shipfx_flash_do_frame(flFrametime);
4008 shockwave_move_all(flFrametime); // update all the shockwaves
4011 // subspace missile strikes
4014 obj_snd_do_frame(); // update the object-linked persistant sounds
4015 game_maybe_update_sound_environment();
4016 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4018 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4020 if ( Game_subspace_effect ) {
4021 game_start_subspace_ambient_sound();
4027 // Maybe render and process the dead-popup
4028 void game_maybe_do_dead_popup(float frametime)
4030 if ( popupdead_is_active() ) {
4032 int choice = popupdead_do_frame(frametime);
4034 if ( Game_mode & GM_NORMAL ) {
4038 if(game_do_cd_mission_check(Game_current_mission_filename)){
4039 gameseq_post_event(GS_EVENT_ENTER_GAME);
4041 gameseq_post_event(GS_EVENT_MAIN_MENU);
4046 gameseq_post_event(GS_EVENT_END_GAME);
4051 if(game_do_cd_mission_check(Game_current_mission_filename)){
4052 gameseq_post_event(GS_EVENT_START_GAME);
4054 gameseq_post_event(GS_EVENT_MAIN_MENU);
4058 // this should only happen during a red alert mission
4061 Assert(The_mission.red_alert);
4062 if(!The_mission.red_alert){
4064 if(game_do_cd_mission_check(Game_current_mission_filename)){
4065 gameseq_post_event(GS_EVENT_START_GAME);
4067 gameseq_post_event(GS_EVENT_MAIN_MENU);
4072 // choose the previous mission
4073 mission_campaign_previous_mission();
4075 if(game_do_cd_mission_check(Game_current_mission_filename)){
4076 gameseq_post_event(GS_EVENT_START_GAME);
4078 gameseq_post_event(GS_EVENT_MAIN_MENU);
4089 case POPUPDEAD_DO_MAIN_HALL:
4090 multi_quit_game(PROMPT_NONE,-1);
4093 case POPUPDEAD_DO_RESPAWN:
4094 multi_respawn_normal();
4095 event_music_player_respawn();
4098 case POPUPDEAD_DO_OBSERVER:
4099 multi_respawn_observer();
4100 event_music_player_respawn_as_observer();
4109 if ( leave_popup ) {
4115 // returns true if player is actually in a game_play stats
4116 int game_actually_playing()
4120 state = gameseq_get_state();
4121 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4127 // Draw the 2D HUD gauges
4128 void game_render_hud_2d()
4130 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4134 HUD_render_2d(flFrametime);
4138 // Draw the 3D-dependant HUD gauges
4139 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4141 g3_start_frame(0); // 0 = turn zbuffering off
4142 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4144 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4145 HUD_render_3d(flFrametime);
4149 game_sunspot_process(flFrametime);
4151 // Diminish the palette effect
4152 game_flash_diminish(flFrametime);
4160 int actually_playing;
4161 fix total_time1, total_time2;
4162 fix render2_time1=0, render2_time2=0;
4163 fix render3_time1=0, render3_time2=0;
4164 fix flip_time1=0, flip_time2=0;
4165 fix clear_time1=0, clear_time2=0;
4171 if (Framerate_delay) {
4172 int start_time = timer_get_milliseconds();
4173 while (timer_get_milliseconds() < start_time + Framerate_delay)
4179 demo_do_frame_start();
4181 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4186 // start timing frame
4187 timing_frame_start();
4189 total_time1 = timer_get_fixed_seconds();
4191 // var to hold which state we are in
4192 actually_playing = game_actually_playing();
4194 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4195 if (!(Game_mode & GM_STANDALONE_SERVER)){
4196 Assert( OBJ_INDEX(Player_obj) >= 0 );
4200 if (Missiontime > Entry_delay_time){
4201 Pre_player_entry = 0;
4203 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4206 // Note: These are done even before the player enters, else buffers can overflow.
4207 if (! (Game_mode & GM_STANDALONE_SERVER)){
4211 shield_frame_init();
4213 if ( Player->control_mode != PCM_NORMAL )
4216 if ( !Pre_player_entry && actually_playing ) {
4217 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4219 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4220 game_process_keys();
4222 // don't read flying controls if we're playing a demo back
4223 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4224 read_player_controls( Player_obj, flFrametime);
4228 // if we're not the master, we may have to send the server-critical ship status button_info bits
4229 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4230 multi_maybe_send_ship_status();
4235 // Reset the whack stuff
4238 // These two lines must be outside of Pre_player_entry code,
4239 // otherwise too many lights are added.
4242 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4246 game_simulation_frame();
4248 // if not actually in a game play state, then return. This condition could only be true in
4249 // a multiplayer game.
4250 if ( !actually_playing ) {
4251 Assert( Game_mode & GM_MULTIPLAYER );
4255 if (!Pre_player_entry) {
4256 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4257 clear_time1 = timer_get_fixed_seconds();
4258 // clear the screen to black
4260 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4264 clear_time2 = timer_get_fixed_seconds();
4265 render3_time1 = timer_get_fixed_seconds();
4266 game_render_frame_setup(&eye_pos, &eye_orient);
4267 game_render_frame( &eye_pos, &eye_orient );
4269 // save the eye position and orientation
4270 if ( Game_mode & GM_MULTIPLAYER ) {
4271 Net_player->s_info.eye_pos = eye_pos;
4272 Net_player->s_info.eye_orient = eye_orient;
4275 hud_show_target_model();
4277 // check to see if we should display the death died popup
4278 if(Game_mode & GM_DEAD_BLEW_UP){
4279 if(Game_mode & GM_MULTIPLAYER){
4280 // catch the situation where we're supposed to be warping out on this transition
4281 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4282 gameseq_post_event(GS_EVENT_DEBRIEF);
4283 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4284 Player_died_popup_wait = -1;
4288 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4289 Player_died_popup_wait = -1;
4295 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4296 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4297 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4298 if(!popupdead_is_active()){
4302 Player_multi_died_check = -1;
4306 render3_time2 = timer_get_fixed_seconds();
4307 render2_time1 = timer_get_fixed_seconds();
4310 game_get_framerate();
4311 game_show_framerate();
4313 game_show_time_left();
4315 // Draw the 2D HUD gauges
4316 if(supernova_active() < 3){
4317 game_render_hud_2d();
4320 game_set_view_clip();
4322 // Draw 3D HUD gauges
4323 game_render_hud_3d(&eye_pos, &eye_orient);
4327 render2_time2 = timer_get_fixed_seconds();
4329 // maybe render and process the dead popup
4330 game_maybe_do_dead_popup(flFrametime);
4332 // start timing frame
4333 timing_frame_stop();
4334 // timing_display(30, 10);
4336 // If a regular popup is active, don't flip (popup code flips)
4337 if( !popup_running_state() ){
4338 flip_time1 = timer_get_fixed_seconds();
4339 game_flip_page_and_time_it();
4340 flip_time2 = timer_get_fixed_seconds();
4344 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4347 game_show_standalone_framerate();
4351 game_do_training_checks();
4354 // process lightning (nebula only)
4357 total_time2 = timer_get_fixed_seconds();
4359 // Got some timing numbers
4360 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4361 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4362 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4363 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4364 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4367 demo_do_frame_end();
4369 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4375 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4376 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4377 // died. This resulted in screwed up death sequences.
4379 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4380 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4381 static int timer_paused=0;
4382 #if defined(TIMER_TEST) && !defined(NDEBUG)
4383 static int stop_count,start_count;
4384 static int time_stopped,time_started;
4386 int saved_timestamp_ticker = -1;
4388 void game_reset_time()
4390 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4394 // Last_time = timer_get_fixed_seconds();
4400 void game_stop_time()
4402 if (timer_paused==0) {
4404 time = timer_get_fixed_seconds();
4405 // Save how much time progressed so far in the frame so we can
4406 // use it when we unpause.
4407 Last_delta_time = time - Last_time;
4409 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4410 if (Last_delta_time < 0) {
4411 #if defined(TIMER_TEST) && !defined(NDEBUG)
4412 Int3(); //get Matt!!!!
4414 Last_delta_time = 0;
4416 #if defined(TIMER_TEST) && !defined(NDEBUG)
4417 time_stopped = time;
4420 // Stop the timer_tick stuff...
4421 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4422 saved_timestamp_ticker = timestamp_ticker;
4426 #if defined(TIMER_TEST) && !defined(NDEBUG)
4431 void game_start_time()
4434 Assert(timer_paused >= 0);
4435 if (timer_paused==0) {
4437 time = timer_get_fixed_seconds();
4438 #if defined(TIMER_TEST) && !defined(NDEBUG)
4440 Int3(); //get Matt!!!!
4443 // Take current time, and set it backwards to account for time
4444 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4445 // will be correct when it goes to calculate the frametime next
4447 Last_time = time - Last_delta_time;
4448 #if defined(TIMER_TEST) && !defined(NDEBUG)
4449 time_started = time;
4452 // Restore the timer_tick stuff...
4453 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4454 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4455 timestamp_ticker = saved_timestamp_ticker;
4456 saved_timestamp_ticker = -1;
4459 #if defined(TIMER_TEST) && !defined(NDEBUG)
4465 void game_set_frametime(int state)
4468 float frame_cap_diff;
4470 thistime = timer_get_fixed_seconds();
4472 if ( Last_time == 0 )
4473 Frametime = F1_0 / 30;
4475 Frametime = thistime - Last_time;
4477 // Frametime = F1_0 / 30;
4479 fix debug_frametime = Frametime; // Just used to display frametime.
4481 // If player hasn't entered mission yet, make frame take 1/4 second.
4482 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4485 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4487 fix frame_speed = F1_0 / Debug_dump_frames;
4489 if (Frametime > frame_speed ){
4490 nprintf(("warning","slow frame: %x\n",Frametime));
4493 thistime = timer_get_fixed_seconds();
4494 Frametime = thistime - Last_time;
4495 } while (Frametime < frame_speed );
4497 Frametime = frame_speed;
4501 Assert( Framerate_cap > 0 );
4503 // Cap the framerate so it doesn't get too high.
4507 cap = F1_0/Framerate_cap;
4508 if (Frametime < cap) {
4509 thistime = cap - Frametime;
4510 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4511 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4513 thistime = timer_get_fixed_seconds();
4517 if((Game_mode & GM_STANDALONE_SERVER) &&
4518 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4520 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4521 Sleep((DWORD)(frame_cap_diff*1000));
4523 thistime += fl2f((frame_cap_diff));
4525 Frametime = thistime - Last_time;
4528 // If framerate is too low, cap it.
4529 if (Frametime > MAX_FRAMETIME) {
4531 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4533 // to remove warnings in release build
4534 debug_frametime = fl2f(flFrametime);
4536 Frametime = MAX_FRAMETIME;
4539 Frametime = fixmul(Frametime, Game_time_compression);
4541 Last_time = thistime;
4542 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4544 flFrametime = f2fl(Frametime);
4545 //if(!(Game_mode & GM_PLAYING_DEMO)){
4546 timestamp_inc(flFrametime);
4548 /* if ((Framecount > 0) && (Framecount < 10)) {
4549 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4554 // This is called from game_do_frame(), and from navmap_do_frame()
4555 void game_update_missiontime()
4557 // TODO JAS: Put in if and move this into game_set_frametime,
4558 // fix navmap to call game_stop/start_time
4559 //if ( !timer_paused )
4560 Missiontime += Frametime;
4563 void game_do_frame()
4565 game_set_frametime(GS_STATE_GAME_PLAY);
4566 game_update_missiontime();
4568 if (Game_mode & GM_STANDALONE_SERVER) {
4569 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4572 if ( game_single_step && (last_single_step == game_single_step) ) {
4573 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4574 while( key_checkch() == 0 )
4576 os_set_title( XSTR( "FreeSpace", 171) );
4577 Last_time = timer_get_fixed_seconds();
4580 last_single_step = game_single_step;
4582 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4583 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4587 Keep_mouse_centered = 0;
4588 monitor_update(); // Update monitor variables
4591 void multi_maybe_do_frame()
4593 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4598 int Joymouse_button_status = 0;
4600 // Flush all input devices
4608 Joymouse_button_status = 0;
4610 //mprintf(("Game flush!\n" ));
4613 // function for multiplayer only which calls game_do_state_common() when running the
4615 void game_do_dc_networking()
4617 Assert( Game_mode & GM_MULTIPLAYER );
4619 game_do_state_common( gameseq_get_state() );
4622 // Call this whenever in a loop, or when you need to check for a keystroke.
4623 int game_check_key()
4629 // convert keypad enter to normal enter
4630 if ((k & KEY_MASK) == KEY_PADENTER)
4631 k = (k & ~KEY_MASK) | KEY_ENTER;
4638 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4639 static int Demo_show_trailer_timestamp = 0;
4641 void demo_reset_trailer_timer()
4643 Demo_show_trailer_timestamp = timer_get_milliseconds();
4646 void demo_maybe_show_trailer(int k)
4649 // if key pressed, reset demo trailer timer
4651 demo_reset_trailer_timer();
4655 // if mouse moved, reset demo trailer timer
4658 mouse_get_delta(&dx, &dy);
4659 if ( (dx > 0) || (dy > 0) ) {
4660 demo_reset_trailer_timer();
4664 // if joystick has moved, reset demo trailer timer
4667 joy_get_delta(&dx, &dy);
4668 if ( (dx > 0) || (dy > 0) ) {
4669 demo_reset_trailer_timer();
4673 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4674 // the low-level code. Ugly, I know... but was the simplest and most
4677 // if 30 seconds since last demo trailer time reset, launch movie
4678 if ( os_foreground() ) {
4679 int now = timer_get_milliseconds();
4680 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4681 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4683 movie_play( NOX("fstrailer2.mve") );
4684 demo_reset_trailer_timer();
4692 // same as game_check_key(), except this is used while actually in the game. Since there
4693 // generally are differences between game control keys and general UI keys, makes sense to
4694 // have seperate functions for each case. If you are not checking a game control while in a
4695 // mission, you should probably be using game_check_key() instead.
4700 if (!os_foreground()) {
4705 // If we're in a single player game, pause it.
4706 if (!(Game_mode & GM_MULTIPLAYER)){
4707 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4708 game_process_pause_key();
4716 demo_maybe_show_trailer(k);
4719 // Move the mouse cursor with the joystick.
4720 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4721 // Move the mouse cursor with the joystick
4725 joy_get_pos( &jx, &jy, &jz, &jr );
4727 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4728 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4731 mouse_get_real_pos( &mx, &my );
4732 mouse_set_pos( mx+dx, my+dy );
4737 m = mouse_down(MOUSE_LEFT_BUTTON);
4739 if ( j != Joymouse_button_status ) {
4740 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4741 Joymouse_button_status = j;
4743 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4744 } else if ( (!j) && (m) ) {
4745 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4750 // if we should be ignoring keys because of some multiplayer situations
4751 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4755 // If a popup is running, don't process all the Fn keys
4756 if( popup_active() ) {
4760 state = gameseq_get_state();
4762 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4765 case KEY_DEBUGGED + KEY_BACKSP:
4770 launch_context_help();
4775 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4777 // don't allow f2 while warping out in multiplayer
4778 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4783 case GS_STATE_INITIAL_PLAYER_SELECT:
4784 case GS_STATE_OPTIONS_MENU:
4785 case GS_STATE_HUD_CONFIG:
4786 case GS_STATE_CONTROL_CONFIG:
4787 case GS_STATE_DEATH_DIED:
4788 case GS_STATE_DEATH_BLEW_UP:
4789 case GS_STATE_VIEW_MEDALS:
4793 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4800 // hotkey selection screen -- only valid from briefing and beyond.
4803 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) ) {
4804 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4810 case KEY_DEBUGGED + KEY_F3:
4811 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4814 case KEY_DEBUGGED + KEY_F4:
4815 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4819 if(Game_mode & GM_MULTIPLAYER){
4820 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4821 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4825 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4826 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4832 case KEY_ESC | KEY_SHIFTED:
4833 // make sure to quit properly out of multiplayer
4834 if(Game_mode & GM_MULTIPLAYER){
4835 multi_quit_game(PROMPT_NONE);
4838 gameseq_post_event( GS_EVENT_QUIT_GAME );
4843 case KEY_DEBUGGED + KEY_P:
4846 case KEY_PRINT_SCRN:
4848 static int counter = 0;
4853 sprintf( tmp_name, NOX("screen%02d"), counter );
4855 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4856 gr_print_screen(tmp_name);
4864 case KEY_SHIFTED | KEY_ENTER: {
4866 #if !defined(NDEBUG)
4868 if ( Game_mode & GM_NORMAL ){
4872 // if we're in multiplayer mode, do some special networking
4873 if(Game_mode & GM_MULTIPLAYER){
4874 debug_console(game_do_dc_networking);
4881 if ( Game_mode & GM_NORMAL )
4895 gameseq_post_event(GS_EVENT_QUIT_GAME);
4898 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4901 void camera_set_position( vector *pos )
4906 void camera_set_orient( matrix *orient )
4908 Camera_orient = *orient;
4911 void camera_set_velocity( vector *vel, int instantaneous )
4913 Camera_desired_velocity.xyz.x = 0.0f;
4914 Camera_desired_velocity.xyz.y = 0.0f;
4915 Camera_desired_velocity.xyz.z = 0.0f;
4917 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4918 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4919 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4921 if ( instantaneous ) {
4922 Camera_velocity = Camera_desired_velocity;
4930 vector new_vel, delta_pos;
4932 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4933 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4934 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4936 Camera_velocity = new_vel;
4938 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4940 vm_vec_add2( &Camera_pos, &delta_pos );
4942 float ot = Camera_time+0.0f;
4944 Camera_time += flFrametime;
4946 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4949 tmp.xyz.z = 4.739f; // always go this fast forward.
4951 // pick x and y velocities so they are always on a
4952 // circle with a 25 m radius.
4954 float tmp_angle = frand()*PI2;
4956 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4957 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4959 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4961 //mprintf(( "Changing velocity!\n" ));
4962 camera_set_velocity( &tmp, 0 );
4965 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4966 vector tmp = { 0.0f, 0.0f, 0.0f };
4967 camera_set_velocity( &tmp, 0 );
4972 void end_demo_campaign_do()
4974 #if defined(FS2_DEMO)
4975 // show upsell screens
4976 demo_upsell_show_screens();
4977 #elif defined(OEM_BUILD)
4978 // show oem upsell screens
4979 oem_upsell_show_screens();
4982 // drop into main hall
4983 gameseq_post_event( GS_EVENT_MAIN_MENU );
4986 // All code to process events. This is the only place
4987 // that you should change the state of the game.
4988 void game_process_event( int current_state, int event )
4990 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4993 case GS_EVENT_SIMULATOR_ROOM:
4994 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4997 case GS_EVENT_MAIN_MENU:
4998 gameseq_set_state(GS_STATE_MAIN_MENU);
5001 case GS_EVENT_OPTIONS_MENU:
5002 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5005 case GS_EVENT_BARRACKS_MENU:
5006 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5009 case GS_EVENT_TECH_MENU:
5010 gameseq_set_state(GS_STATE_TECH_MENU);
5013 case GS_EVENT_TRAINING_MENU:
5014 gameseq_set_state(GS_STATE_TRAINING_MENU);
5017 case GS_EVENT_START_GAME:
5018 Select_default_ship = 0;
5019 Player_multi_died_check = -1;
5020 gameseq_set_state(GS_STATE_CMD_BRIEF);
5023 case GS_EVENT_START_BRIEFING:
5024 gameseq_set_state(GS_STATE_BRIEFING);
5027 case GS_EVENT_DEBRIEF:
5028 // did we end the campaign in the main freespace 2 single player campaign?
5029 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5030 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5032 gameseq_set_state(GS_STATE_DEBRIEF);
5035 Player_multi_died_check = -1;
5038 case GS_EVENT_SHIP_SELECTION:
5039 gameseq_set_state( GS_STATE_SHIP_SELECT );
5042 case GS_EVENT_WEAPON_SELECTION:
5043 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5046 case GS_EVENT_ENTER_GAME:
5048 // maybe start recording a demo
5050 demo_start_record("test.fsd");
5054 if (Game_mode & GM_MULTIPLAYER) {
5055 // if we're respawning, make sure we change the view mode so that the hud shows up
5056 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5060 gameseq_set_state(GS_STATE_GAME_PLAY);
5062 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5065 Player_multi_died_check = -1;
5067 // clear multiplayer button info
5068 extern button_info Multi_ship_status_bi;
5069 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5071 Start_time = f2fl(timer_get_approx_seconds());
5073 mprintf(("Entering game at time = %7.3f\n", Start_time));
5077 case GS_EVENT_START_GAME_QUICK:
5078 Select_default_ship = 1;
5079 gameseq_post_event(GS_EVENT_ENTER_GAME);
5083 case GS_EVENT_END_GAME:
5084 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5085 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5086 gameseq_set_state(GS_STATE_MAIN_MENU);
5091 Player_multi_died_check = -1;
5094 case GS_EVENT_QUIT_GAME:
5095 main_hall_stop_music();
5096 main_hall_stop_ambient();
5097 gameseq_set_state(GS_STATE_QUIT_GAME);
5099 Player_multi_died_check = -1;
5102 case GS_EVENT_GAMEPLAY_HELP:
5103 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5106 case GS_EVENT_PAUSE_GAME:
5107 gameseq_push_state(GS_STATE_GAME_PAUSED);
5110 case GS_EVENT_DEBUG_PAUSE_GAME:
5111 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5114 case GS_EVENT_TRAINING_PAUSE:
5115 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5118 case GS_EVENT_PREVIOUS_STATE:
5119 gameseq_pop_state();
5122 case GS_EVENT_TOGGLE_FULLSCREEN:
5123 #ifndef HARDWARE_ONLY
5125 if ( gr_screen.mode == GR_SOFTWARE ) {
5126 gr_init( GR_640, GR_DIRECTDRAW );
5127 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5128 gr_init( GR_640, GR_SOFTWARE );
5134 case GS_EVENT_TOGGLE_GLIDE:
5136 if ( gr_screen.mode != GR_GLIDE ) {
5137 gr_init( GR_640, GR_GLIDE );
5139 gr_init( GR_640, GR_SOFTWARE );
5144 case GS_EVENT_LOAD_MISSION_MENU:
5145 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5148 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5149 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5152 case GS_EVENT_HUD_CONFIG:
5153 gameseq_push_state( GS_STATE_HUD_CONFIG );
5156 case GS_EVENT_CONTROL_CONFIG:
5157 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5160 case GS_EVENT_DEATH_DIED:
5161 gameseq_set_state( GS_STATE_DEATH_DIED );
5164 case GS_EVENT_DEATH_BLEW_UP:
5165 if ( current_state == GS_STATE_DEATH_DIED ) {
5166 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5167 event_music_player_death();
5169 // multiplayer clients set their extra check here
5170 if(Game_mode & GM_MULTIPLAYER){
5171 // set the multi died absolute last chance check
5172 Player_multi_died_check = time(NULL);
5175 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5179 case GS_EVENT_NEW_CAMPAIGN:
5180 if (!mission_load_up_campaign()){
5181 readyroom_continue_campaign();
5184 Player_multi_died_check = -1;
5187 case GS_EVENT_CAMPAIGN_CHEAT:
5188 if (!mission_load_up_campaign()){
5190 // bash campaign value
5191 extern char Main_hall_campaign_cheat[512];
5194 // look for the mission
5195 for(idx=0; idx<Campaign.num_missions; idx++){
5196 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5197 Campaign.next_mission = idx;
5198 Campaign.prev_mission = idx - 1;
5205 readyroom_continue_campaign();
5208 Player_multi_died_check = -1;
5211 case GS_EVENT_CAMPAIGN_ROOM:
5212 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5215 case GS_EVENT_CMD_BRIEF:
5216 gameseq_set_state(GS_STATE_CMD_BRIEF);
5219 case GS_EVENT_RED_ALERT:
5220 gameseq_set_state(GS_STATE_RED_ALERT);
5223 case GS_EVENT_CREDITS:
5224 gameseq_set_state( GS_STATE_CREDITS );
5227 case GS_EVENT_VIEW_MEDALS:
5228 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5231 case GS_EVENT_SHOW_GOALS:
5232 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5235 case GS_EVENT_HOTKEY_SCREEN:
5236 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5239 // multiplayer stuff follow these comments
5241 case GS_EVENT_MULTI_JOIN_GAME:
5242 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5245 case GS_EVENT_MULTI_HOST_SETUP:
5246 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5249 case GS_EVENT_MULTI_CLIENT_SETUP:
5250 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5253 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5254 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5257 case GS_EVENT_MULTI_STD_WAIT:
5258 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5261 case GS_EVENT_STANDALONE_MAIN:
5262 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5265 case GS_EVENT_MULTI_PAUSE:
5266 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5269 case GS_EVENT_INGAME_PRE_JOIN:
5270 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5273 case GS_EVENT_EVENT_DEBUG:
5274 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5277 // Start a warpout where player automatically goes 70 no matter what
5278 // and can't cancel out of it.
5279 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5280 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5282 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5283 Player->saved_viewer_mode = Viewer_mode;
5284 Player->control_mode = PCM_WARPOUT_STAGE1;
5285 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5286 Warpout_time = 0.0f; // Start timer!
5289 case GS_EVENT_PLAYER_WARPOUT_START:
5290 if ( Player->control_mode != PCM_NORMAL ) {
5291 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5293 Player->saved_viewer_mode = Viewer_mode;
5294 Player->control_mode = PCM_WARPOUT_STAGE1;
5295 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5296 Warpout_time = 0.0f; // Start timer!
5297 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5301 case GS_EVENT_PLAYER_WARPOUT_STOP:
5302 if ( Player->control_mode != PCM_NORMAL ) {
5303 if ( !Warpout_forced ) { // cannot cancel forced warpout
5304 Player->control_mode = PCM_NORMAL;
5305 Viewer_mode = Player->saved_viewer_mode;
5306 hud_subspace_notify_abort();
5307 mprintf(( "Player put back to normal mode.\n" ));
5308 if ( Warpout_sound > -1 ) {
5309 snd_stop( Warpout_sound );
5316 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5317 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5318 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5319 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5321 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5322 shipfx_warpout_start( Player_obj );
5323 Player->control_mode = PCM_WARPOUT_STAGE2;
5324 Player->saved_viewer_mode = Viewer_mode;
5325 Viewer_mode |= VM_WARP_CHASE;
5327 vector tmp = Player_obj->pos;
5329 ship_get_eye( &tmp, &tmp_m, Player_obj );
5330 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5331 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5332 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5334 camera_set_position( &tmp );
5335 camera_set_orient( &Player_obj->orient );
5336 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5338 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5339 camera_set_velocity( &tmp_vel, 1);
5343 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5344 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5345 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5346 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5348 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5349 Player->control_mode = PCM_WARPOUT_STAGE3;
5353 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5354 mprintf(( "Player warped out. Going to debriefing!\n" ));
5355 Player->control_mode = PCM_NORMAL;
5356 Viewer_mode = Player->saved_viewer_mode;
5359 // we have a special debriefing screen for multiplayer furballs
5360 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5361 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5363 // do the normal debriefing for all other situations
5365 gameseq_post_event(GS_EVENT_DEBRIEF);
5369 case GS_EVENT_STANDALONE_POSTGAME:
5370 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5373 case GS_EVENT_INITIAL_PLAYER_SELECT:
5374 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5377 case GS_EVENT_GAME_INIT:
5378 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5379 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5381 // see if the command line option has been set to use the last pilot, and act acoordingly
5382 if( player_select_get_last_pilot() ) {
5383 // always enter the main menu -- do the automatic network startup stuff elsewhere
5384 // so that we still have valid checks for networking modes, etc.
5385 gameseq_set_state(GS_STATE_MAIN_MENU);
5387 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5392 case GS_EVENT_MULTI_MISSION_SYNC:
5393 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5396 case GS_EVENT_MULTI_START_GAME:
5397 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5400 case GS_EVENT_MULTI_HOST_OPTIONS:
5401 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5404 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5405 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5408 case GS_EVENT_TEAM_SELECT:
5409 gameseq_set_state(GS_STATE_TEAM_SELECT);
5412 case GS_EVENT_END_CAMPAIGN:
5413 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5416 case GS_EVENT_END_DEMO:
5417 gameseq_set_state(GS_STATE_END_DEMO);
5420 case GS_EVENT_LOOP_BRIEF:
5421 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5430 // Called when a state is being left.
5431 // The current state is still at old_state, but as soon as
5432 // this function leaves, then the current state will become
5433 // new state. You should never try to change the state
5434 // in here... if you think you need to, you probably really
5435 // need to post an event, not change the state.
5436 void game_leave_state( int old_state, int new_state )
5438 int end_mission = 1;
5440 switch (new_state) {
5441 case GS_STATE_GAME_PAUSED:
5442 case GS_STATE_DEBUG_PAUSED:
5443 case GS_STATE_OPTIONS_MENU:
5444 case GS_STATE_CONTROL_CONFIG:
5445 case GS_STATE_MISSION_LOG_SCROLLBACK:
5446 case GS_STATE_DEATH_DIED:
5447 case GS_STATE_SHOW_GOALS:
5448 case GS_STATE_HOTKEY_SCREEN:
5449 case GS_STATE_MULTI_PAUSED:
5450 case GS_STATE_TRAINING_PAUSED:
5451 case GS_STATE_EVENT_DEBUG:
5452 case GS_STATE_GAMEPLAY_HELP:
5453 end_mission = 0; // these events shouldn't end a mission
5457 switch (old_state) {
5458 case GS_STATE_BRIEFING:
5459 brief_stop_voices();
5460 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5461 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5462 && (new_state != GS_STATE_TEAM_SELECT) ){
5463 common_select_close();
5464 if ( new_state == GS_STATE_MAIN_MENU ) {
5465 freespace_stop_mission();
5469 // COMMAND LINE OPTION
5470 if (Cmdline_multi_stream_chat_to_file){
5471 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5472 cfclose(Multi_chat_stream);
5476 case GS_STATE_DEBRIEF:
5477 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5482 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5483 multi_df_debrief_close();
5486 case GS_STATE_LOAD_MISSION_MENU:
5487 mission_load_menu_close();
5490 case GS_STATE_SIMULATOR_ROOM:
5494 case GS_STATE_CAMPAIGN_ROOM:
5495 campaign_room_close();
5498 case GS_STATE_CMD_BRIEF:
5499 if (new_state == GS_STATE_OPTIONS_MENU) {
5504 if (new_state == GS_STATE_MAIN_MENU)
5505 freespace_stop_mission();
5510 case GS_STATE_RED_ALERT:
5514 case GS_STATE_SHIP_SELECT:
5515 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5516 new_state != GS_STATE_HOTKEY_SCREEN &&
5517 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5518 common_select_close();
5519 if ( new_state == GS_STATE_MAIN_MENU ) {
5520 freespace_stop_mission();
5525 case GS_STATE_WEAPON_SELECT:
5526 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5527 new_state != GS_STATE_HOTKEY_SCREEN &&
5528 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5529 common_select_close();
5530 if ( new_state == GS_STATE_MAIN_MENU ) {
5531 freespace_stop_mission();
5536 case GS_STATE_TEAM_SELECT:
5537 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5538 new_state != GS_STATE_HOTKEY_SCREEN &&
5539 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5540 common_select_close();
5541 if ( new_state == GS_STATE_MAIN_MENU ) {
5542 freespace_stop_mission();
5547 case GS_STATE_MAIN_MENU:
5548 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5555 case GS_STATE_OPTIONS_MENU:
5556 //game_start_time();
5557 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5558 multi_join_clear_game_list();
5560 options_menu_close();
5563 case GS_STATE_BARRACKS_MENU:
5564 if(new_state != GS_STATE_VIEW_MEDALS){
5569 case GS_STATE_MISSION_LOG_SCROLLBACK:
5570 hud_scrollback_close();
5573 case GS_STATE_TRAINING_MENU:
5574 training_menu_close();
5577 case GS_STATE_GAME_PLAY:
5578 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5579 player_save_target_and_weapon_link_prefs();
5580 game_stop_looped_sounds();
5583 sound_env_disable();
5584 joy_ff_stop_effects();
5586 // stop game time under certain conditions
5587 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5592 // shut down any recording or playing demos
5597 // when in multiplayer and going back to the main menu, send a leave game packet
5598 // right away (before calling stop mission). stop_mission was taking to long to
5599 // close mission down and I want people to get notified ASAP.
5600 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5601 multi_quit_game(PROMPT_NONE);
5604 freespace_stop_mission();
5605 Game_time_compression = F1_0;
5609 case GS_STATE_TECH_MENU:
5613 case GS_STATE_TRAINING_PAUSED:
5614 Training_num_lines = 0;
5615 // fall through to GS_STATE_GAME_PAUSED
5617 case GS_STATE_GAME_PAUSED:
5619 if ( end_mission ) {
5624 case GS_STATE_DEBUG_PAUSED:
5627 pause_debug_close();
5631 case GS_STATE_HUD_CONFIG:
5635 // join/start a game
5636 case GS_STATE_MULTI_JOIN_GAME:
5637 if(new_state != GS_STATE_OPTIONS_MENU){
5638 multi_join_game_close();
5642 case GS_STATE_MULTI_HOST_SETUP:
5643 case GS_STATE_MULTI_CLIENT_SETUP:
5644 // if this is just the host going into the options screen, don't do anything
5645 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5649 // close down the proper state
5650 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5651 multi_create_game_close();
5653 multi_game_client_setup_close();
5656 // COMMAND LINE OPTION
5657 if (Cmdline_multi_stream_chat_to_file){
5658 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5659 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5660 cfclose(Multi_chat_stream);
5665 case GS_STATE_CONTROL_CONFIG:
5666 control_config_close();
5669 case GS_STATE_DEATH_DIED:
5670 Game_mode &= ~GM_DEAD_DIED;
5672 // early end while respawning or blowing up in a multiplayer game
5673 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5675 freespace_stop_mission();
5679 case GS_STATE_DEATH_BLEW_UP:
5680 Game_mode &= ~GM_DEAD_BLEW_UP;
5682 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5683 // to determine if I should do anything.
5684 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5686 freespace_stop_mission();
5689 // if we are not respawing as an observer or as a player, our new state will not
5690 // be gameplay state.
5691 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5692 game_stop_time(); // hasn't been called yet!!
5693 freespace_stop_mission();
5699 case GS_STATE_CREDITS:
5703 case GS_STATE_VIEW_MEDALS:
5707 case GS_STATE_SHOW_GOALS:
5708 mission_show_goals_close();
5711 case GS_STATE_HOTKEY_SCREEN:
5712 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5713 mission_hotkey_close();
5717 case GS_STATE_MULTI_MISSION_SYNC:
5718 // if we're moving into the options menu, don't do anything
5719 if(new_state == GS_STATE_OPTIONS_MENU){
5723 Assert( Game_mode & GM_MULTIPLAYER );
5725 if ( new_state == GS_STATE_GAME_PLAY ){
5726 // palette_restore_palette();
5728 // change a couple of flags to indicate our state!!!
5729 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5730 send_netplayer_update_packet();
5732 // set the game mode
5733 Game_mode |= GM_IN_MISSION;
5737 case GS_STATE_VIEW_CUTSCENES:
5738 cutscenes_screen_close();
5741 case GS_STATE_MULTI_STD_WAIT:
5742 multi_standalone_wait_close();
5745 case GS_STATE_STANDALONE_MAIN:
5746 standalone_main_close();
5747 if(new_state == GS_STATE_MULTI_STD_WAIT){
5748 init_multiplayer_stats();
5752 case GS_STATE_MULTI_PAUSED:
5753 // if ( end_mission ){
5758 case GS_STATE_INGAME_PRE_JOIN:
5759 multi_ingame_select_close();
5762 case GS_STATE_STANDALONE_POSTGAME:
5763 multi_standalone_postgame_close();
5766 case GS_STATE_INITIAL_PLAYER_SELECT:
5767 player_select_close();
5770 case GS_STATE_MULTI_START_GAME:
5771 multi_start_game_close();
5774 case GS_STATE_MULTI_HOST_OPTIONS:
5775 multi_host_options_close();
5778 case GS_STATE_END_OF_CAMPAIGN:
5779 mission_campaign_end_close();
5782 case GS_STATE_LOOP_BRIEF:
5788 // Called when a state is being entered.
5789 // The current state is set to the state we're entering at
5790 // this point, and old_state is set to the state we're coming
5791 // from. You should never try to change the state
5792 // in here... if you think you need to, you probably really
5793 // need to post an event, not change the state.
5795 void game_enter_state( int old_state, int new_state )
5797 switch (new_state) {
5798 case GS_STATE_MAIN_MENU:
5799 // in multiplayer mode, be sure that we are not doing networking anymore.
5800 if ( Game_mode & GM_MULTIPLAYER ) {
5801 Assert( Net_player != NULL );
5802 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5805 Game_time_compression = F1_0;
5807 // determine which ship this guy is currently based on
5808 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5811 if (Player->on_bastion) {
5819 case GS_STATE_BRIEFING:
5820 main_hall_stop_music();
5821 main_hall_stop_ambient();
5823 if (Game_mode & GM_NORMAL) {
5824 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5825 // MWA: or from options or hotkey screens
5826 // JH: or if the command brief state already did this
5827 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5828 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5829 && (old_state != GS_STATE_CMD_BRIEF) ) {
5830 if ( !game_start_mission() ) // this should put us into a new state on failure!
5834 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5835 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5836 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5838 Game_time_compression = F1_0;
5840 if ( red_alert_mission() ) {
5841 gameseq_post_event(GS_EVENT_RED_ALERT);
5848 case GS_STATE_DEBRIEF:
5849 game_stop_looped_sounds();
5850 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5851 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5856 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5857 multi_df_debrief_init();
5860 case GS_STATE_LOAD_MISSION_MENU:
5861 mission_load_menu_init();
5864 case GS_STATE_SIMULATOR_ROOM:
5868 case GS_STATE_CAMPAIGN_ROOM:
5869 campaign_room_init();
5872 case GS_STATE_RED_ALERT:
5873 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5877 case GS_STATE_CMD_BRIEF: {
5878 int team_num = 0; // team number used as index for which cmd brief to use.
5880 if (old_state == GS_STATE_OPTIONS_MENU) {
5884 main_hall_stop_music();
5885 main_hall_stop_ambient();
5887 if (Game_mode & GM_NORMAL) {
5888 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5889 // MWA: or from options or hotkey screens
5890 // JH: or if the command brief state already did this
5891 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5892 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5893 if ( !game_start_mission() ) // this should put us into a new state on failure!
5898 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5899 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5900 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5902 cmd_brief_init(team_num);
5908 case GS_STATE_SHIP_SELECT:
5912 case GS_STATE_WEAPON_SELECT:
5913 weapon_select_init();
5916 case GS_STATE_TEAM_SELECT:
5920 case GS_STATE_GAME_PAUSED:
5925 case GS_STATE_DEBUG_PAUSED:
5926 // game_stop_time();
5927 // os_set_title("FreeSpace - PAUSED");
5930 case GS_STATE_TRAINING_PAUSED:
5937 case GS_STATE_OPTIONS_MENU:
5939 options_menu_init();
5942 case GS_STATE_GAME_PLAY:
5943 // coming from the gameplay state or the main menu, we might need to load the mission
5944 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5945 if ( !game_start_mission() ) // this should put us into a new state.
5950 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5951 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5952 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5953 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5954 (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) ) {
5955 // JAS: Used to do all paging here.
5959 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5963 main_hall_stop_music();
5964 main_hall_stop_ambient();
5965 event_music_first_pattern(); // start the first pattern
5968 // special code that restores player ship selection and weapons loadout when doing a quick start
5969 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5970 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5971 wss_direct_restore_loadout();
5975 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5976 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5977 event_music_first_pattern(); // start the first pattern
5980 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5981 event_music_first_pattern(); // start the first pattern
5983 player_restore_target_and_weapon_link_prefs();
5985 Game_mode |= GM_IN_MISSION;
5988 // required to truely make mouse deltas zeroed in debug mouse code
5989 void mouse_force_pos(int x, int y);
5990 if (!Is_standalone) {
5991 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5997 // only start time if in single player, or coming from multi wait state
6000 (Game_mode & GM_NORMAL) &&
6001 (old_state != GS_STATE_VIEW_CUTSCENES)
6003 (Game_mode & GM_MULTIPLAYER) && (
6004 (old_state == GS_STATE_MULTI_PAUSED) ||
6005 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6011 // when coming from the multi paused state, reset the timestamps
6012 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6013 multi_reset_timestamps();
6016 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6017 // initialize all object update details
6018 multi_oo_gameplay_init();
6021 // under certain circumstances, the server should reset the object update rate limiting stuff
6022 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6023 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6025 // reinitialize the rate limiting system for all clients
6026 multi_oo_rate_init_all();
6029 // multiplayer clients should always re-initialize their control info rate limiting system
6030 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6031 multi_oo_rate_init_all();
6035 if(Game_mode & GM_MULTIPLAYER){
6036 multi_ping_reset_players();
6039 Game_subspace_effect = 0;
6040 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6041 Game_subspace_effect = 1;
6042 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6043 game_start_subspace_ambient_sound();
6047 sound_env_set(&Game_sound_env);
6048 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6050 // clear multiplayer button info i
6051 extern button_info Multi_ship_status_bi;
6052 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6055 case GS_STATE_HUD_CONFIG:
6059 case GS_STATE_MULTI_JOIN_GAME:
6060 multi_join_clear_game_list();
6062 if (old_state != GS_STATE_OPTIONS_MENU) {
6063 multi_join_game_init();
6068 case GS_STATE_MULTI_HOST_SETUP:
6069 // don't reinitialize if we're coming back from the host options screen
6070 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6071 multi_create_game_init();
6076 case GS_STATE_MULTI_CLIENT_SETUP:
6077 if (old_state != GS_STATE_OPTIONS_MENU) {
6078 multi_game_client_setup_init();
6083 case GS_STATE_CONTROL_CONFIG:
6084 control_config_init();
6087 case GS_STATE_TECH_MENU:
6091 case GS_STATE_BARRACKS_MENU:
6092 if(old_state != GS_STATE_VIEW_MEDALS){
6097 case GS_STATE_MISSION_LOG_SCROLLBACK:
6098 hud_scrollback_init();
6101 case GS_STATE_DEATH_DIED:
6102 Player_died_time = timestamp(10);
6104 if(!(Game_mode & GM_MULTIPLAYER)){
6105 player_show_death_message();
6107 Game_mode |= GM_DEAD_DIED;
6110 case GS_STATE_DEATH_BLEW_UP:
6111 if ( !popupdead_is_active() ) {
6112 Player_ai->target_objnum = -1;
6115 // stop any local EMP effect
6118 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6119 Game_mode |= GM_DEAD_BLEW_UP;
6120 Show_viewing_from_self = 0;
6122 // timestamp how long we should wait before displaying the died popup
6123 if ( !popupdead_is_active() ) {
6124 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6128 case GS_STATE_GAMEPLAY_HELP:
6129 gameplay_help_init();
6132 case GS_STATE_CREDITS:
6133 main_hall_stop_music();
6134 main_hall_stop_ambient();
6138 case GS_STATE_VIEW_MEDALS:
6139 medal_main_init(Player);
6142 case GS_STATE_SHOW_GOALS:
6143 mission_show_goals_init();
6146 case GS_STATE_HOTKEY_SCREEN:
6147 mission_hotkey_init();
6150 case GS_STATE_MULTI_MISSION_SYNC:
6151 // if we're coming from the options screen, don't do any
6152 if(old_state == GS_STATE_OPTIONS_MENU){
6156 switch(Multi_sync_mode){
6157 case MULTI_SYNC_PRE_BRIEFING:
6158 // if moving from game forming to the team select state
6161 case MULTI_SYNC_POST_BRIEFING:
6162 // if moving from briefing into the mission itself
6165 // tell everyone that we're now loading data
6166 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6167 send_netplayer_update_packet();
6169 // JAS: Used to do all paging here!!!!
6171 Net_player->state = NETPLAYER_STATE_WAITING;
6172 send_netplayer_update_packet();
6174 Game_time_compression = F1_0;
6176 case MULTI_SYNC_INGAME:
6182 case GS_STATE_VIEW_CUTSCENES:
6183 cutscenes_screen_init();
6186 case GS_STATE_MULTI_STD_WAIT:
6187 multi_standalone_wait_init();
6190 case GS_STATE_STANDALONE_MAIN:
6191 // don't initialize if we're coming from one of these 2 states unless there are no
6192 // players left (reset situation)
6193 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6194 standalone_main_init();
6198 case GS_STATE_MULTI_PAUSED:
6202 case GS_STATE_INGAME_PRE_JOIN:
6203 multi_ingame_select_init();
6206 case GS_STATE_STANDALONE_POSTGAME:
6207 multi_standalone_postgame_init();
6210 case GS_STATE_INITIAL_PLAYER_SELECT:
6211 player_select_init();
6214 case GS_STATE_MULTI_START_GAME:
6215 multi_start_game_init();
6218 case GS_STATE_MULTI_HOST_OPTIONS:
6219 multi_host_options_init();
6222 case GS_STATE_END_OF_CAMPAIGN:
6223 mission_campaign_end_init();
6226 case GS_STATE_LOOP_BRIEF:
6233 // do stuff that may need to be done regardless of state
6234 void game_do_state_common(int state,int no_networking)
6236 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6237 snd_do_frame(); // update sound system
6238 event_music_do_frame(); // music needs to play across many states
6240 multi_log_process();
6242 if (no_networking) {
6246 // maybe do a multiplayer frame based on game mode and state type
6247 if (Game_mode & GM_MULTIPLAYER) {
6249 case GS_STATE_OPTIONS_MENU:
6250 case GS_STATE_GAMEPLAY_HELP:
6251 case GS_STATE_HOTKEY_SCREEN:
6252 case GS_STATE_HUD_CONFIG:
6253 case GS_STATE_CONTROL_CONFIG:
6254 case GS_STATE_MISSION_LOG_SCROLLBACK:
6255 case GS_STATE_SHOW_GOALS:
6256 case GS_STATE_VIEW_CUTSCENES:
6257 case GS_STATE_EVENT_DEBUG:
6258 multi_maybe_do_frame();
6262 game_do_networking();
6266 // Called once a frame.
6267 // You should never try to change the state
6268 // in here... if you think you need to, you probably really
6269 // need to post an event, not change the state.
6270 int Game_do_state_should_skip = 0;
6271 void game_do_state(int state)
6273 // always lets the do_state_common() function determine if the state should be skipped
6274 Game_do_state_should_skip = 0;
6276 // legal to set the should skip state anywhere in this function
6277 game_do_state_common(state); // do stuff that may need to be done regardless of state
6279 if(Game_do_state_should_skip){
6284 case GS_STATE_MAIN_MENU:
6285 game_set_frametime(GS_STATE_MAIN_MENU);
6286 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6289 main_hall_do(flFrametime);
6293 case GS_STATE_OPTIONS_MENU:
6294 game_set_frametime(GS_STATE_OPTIONS_MENU);
6295 options_menu_do_frame(flFrametime);
6298 case GS_STATE_BARRACKS_MENU:
6299 game_set_frametime(GS_STATE_BARRACKS_MENU);
6300 barracks_do_frame(flFrametime);
6303 case GS_STATE_TRAINING_MENU:
6304 game_set_frametime(GS_STATE_TRAINING_MENU);
6305 training_menu_do_frame(flFrametime);
6308 case GS_STATE_TECH_MENU:
6309 game_set_frametime(GS_STATE_TECH_MENU);
6310 techroom_do_frame(flFrametime);
6313 case GS_STATE_GAMEPLAY_HELP:
6314 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6315 gameplay_help_do_frame(flFrametime);
6318 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6322 case GS_STATE_GAME_PAUSED:
6326 case GS_STATE_DEBUG_PAUSED:
6328 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6333 case GS_STATE_TRAINING_PAUSED:
6334 game_training_pause_do();
6337 case GS_STATE_LOAD_MISSION_MENU:
6338 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6339 mission_load_menu_do();
6342 case GS_STATE_BRIEFING:
6343 game_set_frametime(GS_STATE_BRIEFING);
6344 brief_do_frame(flFrametime);
6347 case GS_STATE_DEBRIEF:
6348 game_set_frametime(GS_STATE_DEBRIEF);
6349 debrief_do_frame(flFrametime);
6352 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6353 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6354 multi_df_debrief_do();
6357 case GS_STATE_SHIP_SELECT:
6358 game_set_frametime(GS_STATE_SHIP_SELECT);
6359 ship_select_do(flFrametime);
6362 case GS_STATE_WEAPON_SELECT:
6363 game_set_frametime(GS_STATE_WEAPON_SELECT);
6364 weapon_select_do(flFrametime);
6367 case GS_STATE_MISSION_LOG_SCROLLBACK:
6368 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6369 hud_scrollback_do_frame(flFrametime);
6372 case GS_STATE_HUD_CONFIG:
6373 game_set_frametime(GS_STATE_HUD_CONFIG);
6374 hud_config_do_frame(flFrametime);
6377 case GS_STATE_MULTI_JOIN_GAME:
6378 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6379 multi_join_game_do_frame();
6382 case GS_STATE_MULTI_HOST_SETUP:
6383 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6384 multi_create_game_do();
6387 case GS_STATE_MULTI_CLIENT_SETUP:
6388 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6389 multi_game_client_setup_do_frame();
6392 case GS_STATE_CONTROL_CONFIG:
6393 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6394 control_config_do_frame(flFrametime);
6397 case GS_STATE_DEATH_DIED:
6401 case GS_STATE_DEATH_BLEW_UP:
6405 case GS_STATE_SIMULATOR_ROOM:
6406 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6407 sim_room_do_frame(flFrametime);
6410 case GS_STATE_CAMPAIGN_ROOM:
6411 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6412 campaign_room_do_frame(flFrametime);
6415 case GS_STATE_RED_ALERT:
6416 game_set_frametime(GS_STATE_RED_ALERT);
6417 red_alert_do_frame(flFrametime);
6420 case GS_STATE_CMD_BRIEF:
6421 game_set_frametime(GS_STATE_CMD_BRIEF);
6422 cmd_brief_do_frame(flFrametime);
6425 case GS_STATE_CREDITS:
6426 game_set_frametime(GS_STATE_CREDITS);
6427 credits_do_frame(flFrametime);
6430 case GS_STATE_VIEW_MEDALS:
6431 game_set_frametime(GS_STATE_VIEW_MEDALS);
6435 case GS_STATE_SHOW_GOALS:
6436 game_set_frametime(GS_STATE_SHOW_GOALS);
6437 mission_show_goals_do_frame(flFrametime);
6440 case GS_STATE_HOTKEY_SCREEN:
6441 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6442 mission_hotkey_do_frame(flFrametime);
6445 case GS_STATE_VIEW_CUTSCENES:
6446 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6447 cutscenes_screen_do_frame();
6450 case GS_STATE_MULTI_STD_WAIT:
6451 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6452 multi_standalone_wait_do();
6455 case GS_STATE_STANDALONE_MAIN:
6456 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6457 standalone_main_do();
6460 case GS_STATE_MULTI_PAUSED:
6461 game_set_frametime(GS_STATE_MULTI_PAUSED);
6465 case GS_STATE_TEAM_SELECT:
6466 game_set_frametime(GS_STATE_TEAM_SELECT);
6470 case GS_STATE_INGAME_PRE_JOIN:
6471 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6472 multi_ingame_select_do();
6475 case GS_STATE_EVENT_DEBUG:
6477 game_set_frametime(GS_STATE_EVENT_DEBUG);
6478 game_show_event_debug(flFrametime);
6482 case GS_STATE_STANDALONE_POSTGAME:
6483 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6484 multi_standalone_postgame_do();
6487 case GS_STATE_INITIAL_PLAYER_SELECT:
6488 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6492 case GS_STATE_MULTI_MISSION_SYNC:
6493 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6497 case GS_STATE_MULTI_START_GAME:
6498 game_set_frametime(GS_STATE_MULTI_START_GAME);
6499 multi_start_game_do();
6502 case GS_STATE_MULTI_HOST_OPTIONS:
6503 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6504 multi_host_options_do();
6507 case GS_STATE_END_OF_CAMPAIGN:
6508 mission_campaign_end_do();
6511 case GS_STATE_END_DEMO:
6512 game_set_frametime(GS_STATE_END_DEMO);
6513 end_demo_campaign_do();
6516 case GS_STATE_LOOP_BRIEF:
6517 game_set_frametime(GS_STATE_LOOP_BRIEF);
6521 } // end switch(gs_current_state)
6525 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6526 int game_do_ram_check(int ram_in_bytes)
6528 if ( ram_in_bytes < 30*1024*1024 ) {
6529 int allowed_to_run = 1;
6530 if ( ram_in_bytes < 25*1024*1024 ) {
6535 int Freespace_total_ram_MB;
6536 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6538 if ( allowed_to_run ) {
6540 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);
6545 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6546 if ( msgbox_rval == IDCANCEL ) {
6553 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);
6555 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6566 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6567 // If so, copy it over and remove the update directory.
6568 void game_maybe_update_launcher(char *exe_dir)
6571 char src_filename[MAX_PATH];
6572 char dest_filename[MAX_PATH];
6574 strcpy(src_filename, exe_dir);
6575 strcat(src_filename, NOX("\\update\\freespace.exe"));
6577 strcpy(dest_filename, exe_dir);
6578 strcat(dest_filename, NOX("\\freespace.exe"));
6580 // see if src_filename exists
6582 fp = fopen(src_filename, "rb");
6588 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6590 // copy updated freespace.exe to freespace exe dir
6591 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6592 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 );
6596 // delete the file in the update directory
6597 DeleteFile(src_filename);
6599 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6600 char update_dir[MAX_PATH];
6601 strcpy(update_dir, exe_dir);
6602 strcat(update_dir, NOX("\\update"));
6603 RemoveDirectory(update_dir);
6609 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6613 int sub_total_destroyed = 0;
6617 // get the total for all his children
6618 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6619 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6622 // find the # of faces for this _individual_ object
6623 total = submodel_get_num_polys(model_num, sm);
6624 if(strstr(pm->submodel[sm].name, "-destroyed")){
6625 sub_total_destroyed = total;
6629 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6632 *out_total += total + sub_total;
6633 *out_destroyed_total += sub_total_destroyed;
6636 #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);
6637 void game_spew_pof_info()
6639 char *pof_list[1000];
6642 int idx, model_num, i, j;
6644 int total, root_total, model_total, destroyed_total, counted;
6648 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6650 // spew info on all the pofs
6656 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6661 for(idx=0; idx<num_files; idx++, counted++){
6662 sprintf(str, "%s.pof", pof_list[idx]);
6663 model_num = model_load(str, 0, NULL);
6665 pm = model_get(model_num);
6667 // if we have a real model
6672 // go through and print all raw submodels
6673 cfputs("RAW\n", out);
6676 for (i=0; i<pm->n_models; i++) {
6677 total = submodel_get_num_polys(model_num, i);
6679 model_total += total;
6680 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6683 sprintf(str, "Model total %d\n", model_total);
6686 // now go through and do it by LOD
6687 cfputs("BY LOD\n\n", out);
6688 for(i=0; i<pm->n_detail_levels; i++){
6689 sprintf(str, "LOD %d\n", i);
6693 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6695 destroyed_total = 0;
6696 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6697 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6700 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6703 sprintf(str, "TOTAL: %d\n", total + root_total);
6705 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6707 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6710 cfputs("------------------------------------------------------------------------\n\n", out);
6714 if(counted >= MAX_POLYGON_MODELS - 5){
6727 game_spew_pof_info();
6730 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6735 // Don't let more than one instance of Freespace run.
6736 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6738 SetForegroundWindow(hwnd);
6743 // Find out how much RAM is on this machine
6746 ms.dwLength = sizeof(MEMORYSTATUS);
6747 GlobalMemoryStatus(&ms);
6748 Freespace_total_ram = ms.dwTotalPhys;
6750 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6754 if ( ms.dwTotalVirtual < 1024 ) {
6755 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6759 if (!vm_init(24*1024*1024)) {
6760 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 );
6764 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6766 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);
6774 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6775 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6776 seem worth bothering with.
6780 lResult = RegOpenKeyEx(
6781 HKEY_LOCAL_MACHINE, // Where it is
6782 "Software\\Microsoft\\DirectX", // name of key
6783 NULL, // DWORD reserved
6784 KEY_QUERY_VALUE, // Allows all changes
6785 &hKey // Location to store key
6788 if (lResult == ERROR_SUCCESS) {
6790 DWORD dwType, dwLen;
6793 lResult = RegQueryValueEx(
6794 hKey, // Handle to key
6795 "Version", // The values name
6796 NULL, // DWORD reserved
6797 &dwType, // What kind it is
6798 (ubyte *) version, // value to set
6799 &dwLen // How many bytes to set
6802 if (lResult == ERROR_SUCCESS) {
6803 dx_version = atoi(strstr(version, ".") + 1);
6807 DWORD dwType, dwLen;
6810 lResult = RegQueryValueEx(
6811 hKey, // Handle to key
6812 "InstalledVersion", // The values name
6813 NULL, // DWORD reserved
6814 &dwType, // What kind it is
6815 (ubyte *) &val, // value to set
6816 &dwLen // How many bytes to set
6819 if (lResult == ERROR_SUCCESS) {
6827 if (dx_version < 3) {
6828 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6829 "latest version of DirectX at:\n\n"
6830 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6832 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6833 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6838 //=====================================================
6839 // Make sure we're running in the right directory.
6843 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6844 char *p = exe_dir + strlen(exe_dir);
6846 // chop off the filename
6847 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6853 if ( strlen(exe_dir) > 0 ) {
6854 SetCurrentDirectory(exe_dir);
6857 // check for updated freespace.exe
6858 game_maybe_update_launcher(exe_dir);
6866 extern void windebug_memwatch_init();
6867 windebug_memwatch_init();
6871 parse_cmdline(szCmdLine);
6873 #ifdef STANDALONE_ONLY_BUILD
6875 nprintf(("Network", "Standalone running"));
6878 nprintf(("Network", "Standalone running"));
6886 // maybe spew pof stuff
6887 if(Cmdline_spew_pof_info){
6888 game_spew_pof_info();
6893 // non-demo, non-standalone, play the intro movie
6898 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) ){
6900 #if defined(OEM_BUILD)
6901 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6903 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6904 #endif // defined(OEM_BUILD)
6909 if ( !Is_standalone ) {
6911 // release -- movies always play
6914 // 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
6915 movie_play( NOX("intro.mve"), 0 );
6917 // debug version, movie will only play with -showmovies
6918 #elif !defined(NDEBUG)
6920 movie_play( NOX("intro.mve"), 0);
6923 if ( Cmdline_show_movies )
6924 movie_play( NOX("intro.mve"), 0 );
6933 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6935 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6939 // only important for non THREADED mode
6942 state = gameseq_process_events();
6943 if ( state == GS_STATE_QUIT_GAME ){
6950 demo_upsell_show_screens();
6952 #elif defined(OEM_BUILD)
6953 // show upsell screens on exit
6954 oem_upsell_show_screens();
6961 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6967 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6969 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6971 // Do nothing here - RecordExceptionInfo() has already done
6972 // everything that is needed. Actually this code won't even
6973 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6974 // the __except clause.
6978 nprintf(("WinMain", "exceptions shall fall through"));
6980 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6986 // launcher the fslauncher program on exit
6987 void game_launch_launcher_on_exit()
6991 PROCESS_INFORMATION pi;
6992 char cmd_line[2048];
6993 char original_path[1024] = "";
6995 memset( &si, 0, sizeof(STARTUPINFO) );
6999 _getcwd(original_path, 1023);
7001 // set up command line
7002 strcpy(cmd_line, original_path);
7003 strcat(cmd_line, "\\");
7004 strcat(cmd_line, LAUNCHER_FNAME);
7005 strcat(cmd_line, " -straight_to_update");
7007 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7008 cmd_line, // pointer to command line string
7009 NULL, // pointer to process security attributes
7010 NULL, // pointer to thread security attributes
7011 FALSE, // handle inheritance flag
7012 CREATE_DEFAULT_ERROR_MODE, // creation flags
7013 NULL, // pointer to new environment block
7014 NULL, // pointer to current directory name
7015 &si, // pointer to STARTUPINFO
7016 &pi // pointer to PROCESS_INFORMATION
7018 // to eliminate build warnings
7028 // This function is called when FreeSpace terminates normally.
7030 void game_shutdown(void)
7036 // don't ever flip a page on the standalone!
7037 if(!(Game_mode & GM_STANDALONE_SERVER)){
7043 // if the player has left the "player select" screen and quit the game without actually choosing
7044 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7045 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7049 // load up common multiplayer icons
7050 multi_unload_common_icons();
7052 shockwave_close(); // release any memory used by shockwave system
7053 fireball_close(); // free fireball system
7054 ship_close(); // free any memory that was allocated for the ships
7055 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7056 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7057 bm_unload_all(); // free bitmaps
7058 mission_campaign_close(); // close out the campaign stuff
7059 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7061 #ifdef MULTI_USE_LAG
7065 // the menu close functions will unload the bitmaps if they were displayed during the game
7066 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7069 training_menu_close();
7072 extern void joy_close();
7075 audiostream_close();
7077 event_music_close();
7081 // HACKITY HACK HACK
7082 // if this flag is set, we should be firing up the launcher when exiting freespace
7083 extern int Multi_update_fireup_launcher_on_exit;
7084 if(Multi_update_fireup_launcher_on_exit){
7085 game_launch_launcher_on_exit();
7089 // game_stop_looped_sounds()
7091 // This function will call the appropriate stop looped sound functions for those
7092 // modules which use looping sounds. It is not enough just to stop a looping sound
7093 // at the DirectSound level, the game is keeping track of looping sounds, and this
7094 // function is used to inform the game that looping sounds are being halted.
7096 void game_stop_looped_sounds()
7098 hud_stop_looped_locking_sounds();
7099 hud_stop_looped_engine_sounds();
7100 afterburner_stop_sounds();
7101 player_stop_looped_sounds();
7102 obj_snd_stop_all(); // stop all object-linked persistant sounds
7103 game_stop_subspace_ambient_sound();
7104 snd_stop(Radar_static_looping);
7105 Radar_static_looping = -1;
7106 snd_stop(Target_static_looping);
7107 shipfx_stop_engine_wash_sound();
7108 Target_static_looping = -1;
7111 //////////////////////////////////////////////////////////////////////////
7113 // Code for supporting an animating mouse pointer
7116 //////////////////////////////////////////////////////////////////////////
7118 typedef struct animating_obj
7127 static animating_obj Animating_mouse;
7129 // ----------------------------------------------------------------------------
7130 // init_animating_pointer()
7132 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7133 // gets properly initialized
7135 void init_animating_pointer()
7137 Animating_mouse.first_frame = -1;
7138 Animating_mouse.num_frames = 0;
7139 Animating_mouse.current_frame = -1;
7140 Animating_mouse.time = 0.0f;
7141 Animating_mouse.elapsed_time = 0.0f;
7144 // ----------------------------------------------------------------------------
7145 // load_animating_pointer()
7147 // Called at game init to load in the frames for the animating mouse pointer
7149 // input: filename => filename of animation file that holds the animation
7151 void load_animating_pointer(char *filename, int dx, int dy)
7156 init_animating_pointer();
7158 am = &Animating_mouse;
7159 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7160 if ( am->first_frame == -1 )
7161 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7162 am->current_frame = 0;
7163 am->time = am->num_frames / i2fl(fps);
7166 // ----------------------------------------------------------------------------
7167 // unload_animating_pointer()
7169 // Called at game shutdown to free the memory used to store the animation frames
7171 void unload_animating_pointer()
7176 am = &Animating_mouse;
7177 for ( i = 0; i < am->num_frames; i++ ) {
7178 Assert( (am->first_frame+i) >= 0 );
7179 bm_release(am->first_frame + i);
7182 am->first_frame = -1;
7184 am->current_frame = -1;
7187 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7188 void game_render_mouse(float frametime)
7193 // if animating cursor exists, play the next frame
7194 am = &Animating_mouse;
7195 if ( am->first_frame != -1 ) {
7196 mouse_get_pos(&mx, &my);
7197 am->elapsed_time += frametime;
7198 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7199 if ( am->current_frame >= am->num_frames ) {
7200 am->current_frame = 0;
7201 am->elapsed_time = 0.0f;
7203 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7207 // ----------------------------------------------------------------------------
7208 // game_maybe_draw_mouse()
7210 // determines whether to draw the mouse pointer at all, and what frame of
7211 // animation to use if the mouse is animating
7213 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7215 // input: frametime => elapsed frame time in seconds since last call
7217 void game_maybe_draw_mouse(float frametime)
7221 game_state = gameseq_get_state();
7223 switch ( game_state ) {
7224 case GS_STATE_GAME_PAUSED:
7225 // case GS_STATE_MULTI_PAUSED:
7226 case GS_STATE_GAME_PLAY:
7227 case GS_STATE_DEATH_DIED:
7228 case GS_STATE_DEATH_BLEW_UP:
7229 if ( popup_active() || popupdead_is_active() ) {
7241 if ( !Mouse_hidden )
7242 game_render_mouse(frametime);
7246 void game_do_training_checks()
7250 waypoint_list *wplp;
7252 if (Training_context & TRAINING_CONTEXT_SPEED) {
7253 s = (int) Player_obj->phys_info.fspeed;
7254 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7255 if (!Training_context_speed_set) {
7256 Training_context_speed_set = 1;
7257 Training_context_speed_timestamp = timestamp();
7261 Training_context_speed_set = 0;
7264 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7265 wplp = &Waypoint_lists[Training_context_path];
7266 if (wplp->count > Training_context_goal_waypoint) {
7267 i = Training_context_goal_waypoint;
7269 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7270 if (d <= Training_context_distance) {
7271 Training_context_at_waypoint = i;
7272 if (Training_context_goal_waypoint == i) {
7273 Training_context_goal_waypoint++;
7274 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7281 if (i == wplp->count)
7284 } while (i != Training_context_goal_waypoint);
7288 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7289 Players_target = Player_ai->target_objnum;
7290 Players_targeted_subsys = Player_ai->targeted_subsys;
7291 Players_target_timestamp = timestamp();
7295 /////////// Following is for event debug view screen
7299 #define EVENT_DEBUG_MAX 5000
7300 #define EVENT_DEBUG_EVENT 0x8000
7302 int Event_debug_index[EVENT_DEBUG_MAX];
7305 void game_add_event_debug_index(int n, int indent)
7307 if (ED_count < EVENT_DEBUG_MAX)
7308 Event_debug_index[ED_count++] = n | (indent << 16);
7311 void game_add_event_debug_sexp(int n, int indent)
7316 if (Sexp_nodes[n].first >= 0) {
7317 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7318 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7322 game_add_event_debug_index(n, indent);
7323 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7324 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7326 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7329 void game_event_debug_init()
7334 for (e=0; e<Num_mission_events; e++) {
7335 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7336 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7340 void game_show_event_debug(float frametime)
7344 int font_height, font_width;
7346 static int scroll_offset = 0;
7348 k = game_check_key();
7354 if (scroll_offset < 0)
7364 scroll_offset -= 20;
7365 if (scroll_offset < 0)
7370 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7374 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7380 gr_set_color_fast(&Color_bright);
7382 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7384 gr_set_color_fast(&Color_normal);
7386 gr_get_string_size(&font_width, &font_height, NOX("test"));
7387 y_max = gr_screen.max_h - font_height - 5;
7391 while (k < ED_count) {
7392 if (y_index > y_max)
7395 z = Event_debug_index[k];
7396 if (z & EVENT_DEBUG_EVENT) {
7398 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7399 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7400 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7401 Mission_events[z].repeat_count, Mission_events[z].interval);
7409 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7410 switch (Sexp_nodes[z & 0x7fff].value) {
7412 strcat(buf, NOX(" (True)"));
7416 strcat(buf, NOX(" (False)"));
7419 case SEXP_KNOWN_TRUE:
7420 strcat(buf, NOX(" (Always true)"));
7423 case SEXP_KNOWN_FALSE:
7424 strcat(buf, NOX(" (Always false)"));
7427 case SEXP_CANT_EVAL:
7428 strcat(buf, NOX(" (Can't eval)"));
7432 case SEXP_NAN_FOREVER:
7433 strcat(buf, NOX(" (Not a number)"));
7438 gr_printf(10, y_index, buf);
7439 y_index += font_height;
7452 extern int Tmap_npixels;
7454 int Tmap_num_too_big = 0;
7455 int Num_models_needing_splitting = 0;
7457 void Time_model( int modelnum )
7459 // mprintf(( "Timing ship '%s'\n", si->name ));
7461 vector eye_pos, model_pos;
7462 matrix eye_orient, model_orient;
7464 polymodel *pm = model_get( modelnum );
7466 int l = strlen(pm->filename);
7468 if ( (l == '/') || (l=='\\') || (l==':')) {
7474 char *pof_file = &pm->filename[l];
7476 int model_needs_splitting = 0;
7478 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7480 for (i=0; i<pm->n_textures; i++ ) {
7481 char filename[1024];
7484 int bmp_num = pm->original_textures[i];
7485 if ( bmp_num > -1 ) {
7486 bm_get_palette(pm->original_textures[i], pal, filename );
7488 bm_get_info( pm->original_textures[i],&w, &h );
7491 if ( (w > 512) || (h > 512) ) {
7492 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7494 model_needs_splitting++;
7497 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7501 if ( model_needs_splitting ) {
7502 Num_models_needing_splitting++;
7504 eye_orient = model_orient = vmd_identity_matrix;
7505 eye_pos = model_pos = vmd_zero_vector;
7507 eye_pos.xyz.z = -pm->rad*2.0f;
7509 vector eye_to_model;
7511 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7512 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7514 fix t1 = timer_get_fixed_seconds();
7517 ta.p = ta.b = ta.h = 0.0f;
7522 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7524 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7526 modelstats_num_polys = modelstats_num_verts = 0;
7528 while( ta.h < PI2 ) {
7531 vm_angles_2_matrix(&m1, &ta );
7532 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7539 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7541 model_clear_instance( modelnum );
7542 model_set_detail_level(0); // use highest detail level
7543 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7551 int k = key_inkey();
7552 if ( k == KEY_ESC ) {
7557 fix t2 = timer_get_fixed_seconds();
7559 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7560 //bitmaps_used_this_frame /= framecount;
7562 modelstats_num_polys /= framecount;
7563 modelstats_num_verts /= framecount;
7565 Tmap_npixels /=framecount;
7568 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7569 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 );
7570 // 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 );
7576 int Time_models = 0;
7577 DCF_BOOL( time_models, Time_models );
7579 void Do_model_timings_test()
7583 if ( !Time_models ) return;
7585 mprintf(( "Timing models!\n" ));
7589 ubyte model_used[MAX_POLYGON_MODELS];
7590 int model_id[MAX_POLYGON_MODELS];
7591 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7596 for (i=0; i<Num_ship_types; i++ ) {
7597 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7599 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7600 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7603 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7604 if ( !Texture_fp ) return;
7606 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7607 if ( !Time_fp ) return;
7609 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7610 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7612 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7613 if ( model_used[i] ) {
7614 Time_model( model_id[i] );
7618 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7619 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7628 // Call this function when you want to inform the player that a feature is not
7629 // enabled in the DEMO version of FreSpace
7630 void game_feature_not_in_demo_popup()
7632 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7635 // format the specified time (fixed point) into a nice string
7636 void game_format_time(fix m_time,char *time_str)
7639 int hours,minutes,seconds;
7642 mtime = f2fl(m_time);
7644 // get the hours, minutes and seconds
7645 hours = (int)(mtime / 3600.0f);
7647 mtime -= (3600.0f * (float)hours);
7649 seconds = (int)mtime%60;
7650 minutes = (int)mtime/60;
7652 // print the hour if necessary
7654 sprintf(time_str,XSTR( "%d:", 201),hours);
7655 // if there are less than 10 minutes, print a leading 0
7657 strcpy(tmp,NOX("0"));
7658 strcat(time_str,tmp);
7662 // print the minutes
7664 sprintf(tmp,XSTR( "%d:", 201),minutes);
7665 strcat(time_str,tmp);
7667 sprintf(time_str,XSTR( "%d:", 201),minutes);
7670 // print the seconds
7672 strcpy(tmp,NOX("0"));
7673 strcat(time_str,tmp);
7675 sprintf(tmp,"%d",seconds);
7676 strcat(time_str,tmp);
7679 // Stuff version string in *str.
7680 void get_version_string(char *str)
7683 if ( FS_VERSION_BUILD == 0 ) {
7684 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7686 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7689 #if defined (FS2_DEMO)
7691 #elif defined (OEM_BUILD)
7692 strcat(str, " (OEM)");
7698 char myname[_MAX_PATH];
7699 int namelen, major, minor, build, waste;
7700 unsigned int buf_size;
7706 // Find my EXE file name
7707 hMod = GetModuleHandle(NULL);
7708 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7710 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7711 infop = (char *)malloc(version_size);
7712 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7714 // get the product version
7715 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7716 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7718 sprintf(str,"Dv%d.%02d",major, minor);
7720 sprintf(str,"v%d.%02d",major, minor);
7725 void get_version_string_short(char *str)
7727 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7730 // ----------------------------------------------------------------
7732 // OEM UPSELL SCREENS BEGIN
7734 // ----------------------------------------------------------------
7735 #if defined(OEM_BUILD)
7737 #define NUM_OEM_UPSELL_SCREENS 3
7738 #define OEM_UPSELL_SCREEN_DELAY 10000
7740 static int Oem_upsell_bitmaps_loaded = 0;
7741 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7742 static int Oem_upsell_screen_number = 0;
7743 static int Oem_upsell_show_next_bitmap_time;
7746 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7759 static int Oem_normal_cursor = -1;
7760 static int Oem_web_cursor = -1;
7761 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7762 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7764 void oem_upsell_next_screen()
7766 Oem_upsell_screen_number++;
7767 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7768 // extra long delay, mouse shown on last upsell
7769 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7773 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7777 void oem_upsell_load_bitmaps()
7781 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7782 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7786 void oem_upsell_unload_bitmaps()
7790 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7791 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7792 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7797 Oem_upsell_bitmaps_loaded = 0;
7800 // clickable hotspot on 3rd OEM upsell screen
7801 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7803 28, 350, 287, 96 // x, y, w, h
7806 45, 561, 460, 152 // x, y, w, h
7810 void oem_upsell_show_screens()
7812 int current_time, k;
7815 if ( !Oem_upsell_bitmaps_loaded ) {
7816 oem_upsell_load_bitmaps();
7817 Oem_upsell_bitmaps_loaded = 1;
7820 // may use upsell screens more than once
7821 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7822 Oem_upsell_screen_number = 0;
7828 int nframes; // used to pass, not really needed (should be 1)
7829 Oem_normal_cursor = gr_get_cursor_bitmap();
7830 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7831 Assert(Oem_web_cursor >= 0);
7832 if (Oem_web_cursor < 0) {
7833 Oem_web_cursor = Oem_normal_cursor;
7838 //oem_reset_trailer_timer();
7840 current_time = timer_get_milliseconds();
7845 // advance screen on keypress or timeout
7846 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7847 oem_upsell_next_screen();
7850 // check if we are done
7851 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7852 Oem_upsell_screen_number--;
7855 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7860 // show me the upsell
7861 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7862 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7866 // if this is the 3rd upsell, make it clickable, d00d
7867 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7869 int button_state = mouse_get_pos(&mx, &my);
7870 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])
7871 && (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]) )
7874 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7877 if (button_state & MOUSE_LEFT_BUTTON) {
7879 multi_pxo_url(OEM_UPSELL_URL);
7883 // switch cursor back to normal one
7884 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7889 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7899 oem_upsell_unload_bitmaps();
7901 // switch cursor back to normal one
7902 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7906 #endif // defined(OEM_BUILD)
7907 // ----------------------------------------------------------------
7909 // OEM UPSELL SCREENS END
7911 // ----------------------------------------------------------------
7915 // ----------------------------------------------------------------
7917 // DEMO UPSELL SCREENS BEGIN
7919 // ----------------------------------------------------------------
7923 //#define NUM_DEMO_UPSELL_SCREENS 4
7925 #define NUM_DEMO_UPSELL_SCREENS 2
7926 #define DEMO_UPSELL_SCREEN_DELAY 3000
7928 static int Demo_upsell_bitmaps_loaded = 0;
7929 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7930 static int Demo_upsell_screen_number = 0;
7931 static int Demo_upsell_show_next_bitmap_time;
7934 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7947 void demo_upsell_next_screen()
7949 Demo_upsell_screen_number++;
7950 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7951 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7953 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7957 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7958 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7959 #ifndef HARDWARE_ONLY
7960 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7967 void demo_upsell_load_bitmaps()
7971 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7972 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7976 void demo_upsell_unload_bitmaps()
7980 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7981 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7982 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7987 Demo_upsell_bitmaps_loaded = 0;
7990 void demo_upsell_show_screens()
7992 int current_time, k;
7995 if ( !Demo_upsell_bitmaps_loaded ) {
7996 demo_upsell_load_bitmaps();
7997 Demo_upsell_bitmaps_loaded = 1;
8000 // may use upsell screens more than once
8001 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8002 Demo_upsell_screen_number = 0;
8009 demo_reset_trailer_timer();
8011 current_time = timer_get_milliseconds();
8018 // don't time out, wait for keypress
8020 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8021 demo_upsell_next_screen();
8026 demo_upsell_next_screen();
8029 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8030 Demo_upsell_screen_number--;
8033 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8038 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8039 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8044 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8054 demo_upsell_unload_bitmaps();
8059 // ----------------------------------------------------------------
8061 // DEMO UPSELL SCREENS END
8063 // ----------------------------------------------------------------
8066 // ----------------------------------------------------------------
8068 // Subspace Ambient Sound START
8070 // ----------------------------------------------------------------
8072 static int Subspace_ambient_left_channel = -1;
8073 static int Subspace_ambient_right_channel = -1;
8076 void game_start_subspace_ambient_sound()
8078 if ( Subspace_ambient_left_channel < 0 ) {
8079 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8082 if ( Subspace_ambient_right_channel < 0 ) {
8083 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8087 void game_stop_subspace_ambient_sound()
8089 if ( Subspace_ambient_left_channel >= 0 ) {
8090 snd_stop(Subspace_ambient_left_channel);
8091 Subspace_ambient_left_channel = -1;
8094 if ( Subspace_ambient_right_channel >= 0 ) {
8095 snd_stop(Subspace_ambient_right_channel);
8096 Subspace_ambient_right_channel = -1;
8100 // ----------------------------------------------------------------
8102 // Subspace Ambient Sound END
8104 // ----------------------------------------------------------------
8106 // ----------------------------------------------------------------
8108 // CDROM detection code START
8110 // ----------------------------------------------------------------
8112 #define CD_SIZE_72_MINUTE_MAX (697000000)
8114 uint game_get_cd_used_space(char *path)
8118 char use_path[512] = "";
8119 char sub_path[512] = "";
8120 WIN32_FIND_DATA find;
8123 // recurse through all files and directories
8124 strcpy(use_path, path);
8125 strcat(use_path, "*.*");
8126 find_handle = FindFirstFile(use_path, &find);
8129 if(find_handle == INVALID_HANDLE_VALUE){
8135 // subdirectory. make sure to ignore . and ..
8136 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8138 strcpy(sub_path, path);
8139 strcat(sub_path, find.cFileName);
8140 strcat(sub_path, "\\");
8141 total += game_get_cd_used_space(sub_path);
8143 total += (uint)find.nFileSizeLow;
8145 } while(FindNextFile(find_handle, &find));
8148 FindClose(find_handle);
8160 // if volume_name is non-null, the CD name must match that
8161 int find_freespace_cd(char *volume_name)
8164 char oldpath[MAX_PATH];
8168 int volume_match = 0;
8172 GetCurrentDirectory(MAX_PATH, oldpath);
8174 for (i = 0; i < 26; i++)
8180 path[0] = (char)('A'+i);
8181 if (GetDriveType(path) == DRIVE_CDROM) {
8183 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8184 nprintf(("CD", "CD volume: %s\n", volume));
8186 // check for any CD volume
8187 int volume1_present = 0;
8188 int volume2_present = 0;
8189 int volume3_present = 0;
8191 char full_check[512] = "";
8193 // look for setup.exe
8194 strcpy(full_check, path);
8195 strcat(full_check, "setup.exe");
8196 find_handle = _findfirst(full_check, &find);
8197 if(find_handle != -1){
8198 volume1_present = 1;
8199 _findclose(find_handle);
8202 // look for intro.mve
8203 strcpy(full_check, path);
8204 strcat(full_check, "intro.mve");
8205 find_handle = _findfirst(full_check, &find);
8206 if(find_handle != -1){
8207 volume2_present = 1;
8208 _findclose(find_handle);
8211 // look for endpart1.mve
8212 strcpy(full_check, path);
8213 strcat(full_check, "endpart1.mve");
8214 find_handle = _findfirst(full_check, &find);
8215 if(find_handle != -1){
8216 volume3_present = 1;
8217 _findclose(find_handle);
8220 // see if we have the specific CD we're looking for
8221 if ( volume_name ) {
8223 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8227 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8231 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8235 if ( volume1_present || volume2_present || volume3_present ) {
8240 // 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
8241 if ( volume_match ){
8243 // 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
8244 if(volume2_present || volume3_present) {
8245 // first step - check to make sure its a cdrom
8246 if(GetDriveType(path) != DRIVE_CDROM){
8250 #if !defined(OEM_BUILD)
8251 // oem not on 80 min cds, so dont check tha size
8253 uint used_space = game_get_cd_used_space(path);
8254 if(used_space < CD_SIZE_72_MINUTE_MAX){
8257 #endif // !defined(OEM_BUILD)
8265 #endif // RELEASE_REAL
8271 SetCurrentDirectory(oldpath);
8280 int set_cdrom_path(int drive_num)
8284 if (drive_num < 0) { //no CD
8286 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8289 strcpy(Game_CDROM_dir,""); //set directory
8293 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8309 i = find_freespace_cd();
8311 rval = set_cdrom_path(i);
8315 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8317 nprintf(("CD", "FreeSpace CD not found\n"));
8325 int Last_cd_label_found = 0;
8326 char Last_cd_label[256];
8328 int game_cd_changed()
8335 if ( strlen(Game_CDROM_dir) == 0 ) {
8339 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8341 if ( found != Last_cd_label_found ) {
8342 Last_cd_label_found = found;
8344 mprintf(( "CD '%s' was inserted\n", label ));
8347 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8351 if ( Last_cd_label_found ) {
8352 if ( !stricmp( Last_cd_label, label )) {
8353 //mprintf(( "CD didn't change\n" ));
8355 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8359 // none found before, none found now.
8360 //mprintf(( "still no CD...\n" ));
8364 Last_cd_label_found = found;
8366 strcpy( Last_cd_label, label );
8368 strcpy( Last_cd_label, "" );
8379 // check if _any_ FreeSpace2 CDs are in the drive
8380 // return: 1 => CD now in drive
8381 // 0 => Could not find CD, they refuse to put it in the drive
8382 int game_do_cd_check(char *volume_name)
8384 #if !defined(GAME_CD_CHECK)
8390 int num_attempts = 0;
8391 int refresh_files = 0;
8393 int path_set_ok, popup_rval;
8395 cd_drive_num = find_freespace_cd(volume_name);
8396 path_set_ok = set_cdrom_path(cd_drive_num);
8397 if ( path_set_ok ) {
8399 if ( refresh_files ) {
8411 // no CD found, so prompt user
8412 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8414 if ( popup_rval != 1 ) {
8419 if ( num_attempts++ > 5 ) {
8430 // check if _any_ FreeSpace2 CDs are in the drive
8431 // return: 1 => CD now in drive
8432 // 0 => Could not find CD, they refuse to put it in the drive
8433 int game_do_cd_check_specific(char *volume_name, int cdnum)
8438 int num_attempts = 0;
8439 int refresh_files = 0;
8441 int path_set_ok, popup_rval;
8443 cd_drive_num = find_freespace_cd(volume_name);
8444 path_set_ok = set_cdrom_path(cd_drive_num);
8445 if ( path_set_ok ) {
8447 if ( refresh_files ) {
8458 // no CD found, so prompt user
8459 #if defined(DVD_MESSAGE_HACK)
8460 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8462 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8465 if ( popup_rval != 1 ) {
8470 if ( num_attempts++ > 5 ) {
8480 // only need to do this in RELEASE_REAL
8481 int game_do_cd_mission_check(char *filename)
8487 fs_builtin_mission *m = game_find_builtin_mission(filename);
8489 // check for changed CD
8490 if(game_cd_changed()){
8495 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8499 // not builtin, so do a general check (any FS2 CD will do)
8501 return game_do_cd_check();
8504 // does not have any CD requirement, do a general check
8505 if(strlen(m->cd_volume) <= 0){
8506 return game_do_cd_check();
8510 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8512 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8514 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8517 return game_do_cd_check();
8520 // did we find the cd?
8521 if(find_freespace_cd(m->cd_volume) >= 0){
8525 // make sure the volume exists
8526 int num_attempts = 0;
8527 int refresh_files = 0;
8529 int path_set_ok, popup_rval;
8531 cd_drive_num = find_freespace_cd(m->cd_volume);
8532 path_set_ok = set_cdrom_path(cd_drive_num);
8533 if ( path_set_ok ) {
8535 if ( refresh_files ) {
8542 // no CD found, so prompt user
8543 #if defined(DVD_MESSAGE_HACK)
8544 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8546 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8550 if ( popup_rval != 1 ) {
8555 if ( num_attempts++ > 5 ) {
8567 // ----------------------------------------------------------------
8569 // CDROM detection code END
8571 // ----------------------------------------------------------------
8573 // ----------------------------------------------------------------
8574 // SHIPS TBL VERIFICATION STUFF
8577 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8578 #define NUM_SHIPS_TBL_CHECKSUMS 1
8581 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8582 1696074201, // FS2 demo
8586 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8587 -463907578, // US - beta 1
8588 1696074201, // FS2 demo
8591 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8592 // -1022810006, // 1.0 FULL
8593 -1254285366 // 1.2 FULL (German)
8597 void verify_ships_tbl()
8601 Game_ships_tbl_valid = 1;
8607 // detect if the packfile exists
8608 CFILE *detect = cfopen("ships.tbl", "rb");
8609 Game_ships_tbl_valid = 0;
8613 Game_ships_tbl_valid = 0;
8617 // get the long checksum of the file
8619 cfseek(detect, 0, SEEK_SET);
8620 cf_chksum_long(detect, &file_checksum);
8624 // now compare the checksum/filesize against known #'s
8625 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8626 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8627 Game_ships_tbl_valid = 1;
8634 DCF(shipspew, "display the checksum for the current ships.tbl")
8637 CFILE *detect = cfopen("ships.tbl", "rb");
8638 // get the long checksum of the file
8640 cfseek(detect, 0, SEEK_SET);
8641 cf_chksum_long(detect, &file_checksum);
8644 dc_printf("%d", file_checksum);
8647 // ----------------------------------------------------------------
8648 // WEAPONS TBL VERIFICATION STUFF
8651 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8652 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8655 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8656 -266420030, // demo 1
8660 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8661 141718090, // US - beta 1
8662 -266420030, // demo 1
8665 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8666 // 399297860, // 1.0 FULL
8667 -553984927 // 1.2 FULL (german)
8671 void verify_weapons_tbl()
8675 Game_weapons_tbl_valid = 1;
8681 // detect if the packfile exists
8682 CFILE *detect = cfopen("weapons.tbl", "rb");
8683 Game_weapons_tbl_valid = 0;
8687 Game_weapons_tbl_valid = 0;
8691 // get the long checksum of the file
8693 cfseek(detect, 0, SEEK_SET);
8694 cf_chksum_long(detect, &file_checksum);
8698 // now compare the checksum/filesize against known #'s
8699 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8700 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8701 Game_weapons_tbl_valid = 1;
8708 DCF(wepspew, "display the checksum for the current weapons.tbl")
8711 CFILE *detect = cfopen("weapons.tbl", "rb");
8712 // get the long checksum of the file
8714 cfseek(detect, 0, SEEK_SET);
8715 cf_chksum_long(detect, &file_checksum);
8718 dc_printf("%d", file_checksum);
8721 // if the game is running using hacked data
8722 int game_hacked_data()
8725 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8733 void display_title_screen()
8735 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8736 ///int title_bitmap;
8739 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8740 if (title_bitmap == -1) {
8746 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8747 extern void d3d_start_frame();
8753 gr_set_bitmap(title_bitmap);
8760 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8761 extern void d3d_stop_frame();
8769 bm_unload(title_bitmap);
8770 #endif // FS2_DEMO || OEM_BUILD
8773 // return true if the game is running with "low memory", which is less than 48MB
8774 bool game_using_low_mem()
8776 if (Use_low_mem == 0) {