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.24 2002/08/31 01:39:13 theoddone33
19 * Speed up the renderer a tad
21 * Revision 1.23 2002/08/04 02:31:00 relnev
22 * make numlock not overlap with pause
24 * Revision 1.22 2002/08/02 23:07:03 relnev
25 * don't access the mouse in standalone mode
27 * Revision 1.21 2002/07/28 05:05:08 relnev
28 * removed some old stuff
30 * Revision 1.20 2002/07/24 00:20:41 relnev
33 * Revision 1.19 2002/06/17 06:33:08 relnev
34 * ryan's struct patch for gcc 2.95
36 * Revision 1.18 2002/06/16 04:46:33 relnev
37 * set up correct checksums for demo
39 * Revision 1.17 2002/06/09 04:41:17 relnev
40 * added copyright header
42 * Revision 1.16 2002/06/09 03:16:04 relnev
45 * removed unneeded asm, old sdl 2d setup.
47 * fixed crash caused by opengl_get_region.
49 * Revision 1.15 2002/06/05 08:05:28 relnev
50 * stub/warning removal.
52 * reworked the sound code.
54 * Revision 1.14 2002/06/05 04:03:32 relnev
55 * finished cfilesystem.
57 * removed some old code.
59 * fixed mouse save off-by-one.
63 * Revision 1.13 2002/06/02 04:26:34 relnev
66 * Revision 1.12 2002/06/02 00:31:35 relnev
67 * implemented osregistry
69 * Revision 1.11 2002/06/01 09:00:34 relnev
70 * silly debug memmanager
72 * Revision 1.10 2002/06/01 07:12:32 relnev
73 * a few NDEBUG updates.
75 * removed a few warnings.
77 * Revision 1.9 2002/05/31 03:05:59 relnev
80 * Revision 1.8 2002/05/29 02:52:32 theoddone33
81 * Enable OpenGL renderer
83 * Revision 1.7 2002/05/28 08:52:03 relnev
84 * implemented two assembly stubs.
86 * cleaned up a few warnings.
88 * added a little demo hackery to make it progress a little farther.
90 * Revision 1.6 2002/05/28 06:28:20 theoddone33
91 * Filesystem mods, actually reads some data files now
93 * Revision 1.5 2002/05/28 04:07:28 theoddone33
94 * New graphics stubbing arrangement
96 * Revision 1.4 2002/05/27 22:46:52 theoddone33
97 * Remove more undefined symbols
99 * Revision 1.3 2002/05/26 23:31:18 relnev
100 * added a few files that needed to be compiled
102 * freespace.cpp: now compiles
104 * Revision 1.2 2002/05/07 03:16:44 theoddone33
105 * The Great Newline Fix
107 * Revision 1.1.1.1 2002/05/03 03:28:09 root
111 * 201 6/16/00 3:15p Jefff
112 * sim of the year dvd version changes, a few german soty localization
115 * 200 11/03/99 11:06a Jefff
118 * 199 10/26/99 5:07p Jamest
119 * fixed jeffs dumb debug code
121 * 198 10/25/99 5:53p Jefff
122 * call control_config_common_init() on startup
124 * 197 10/14/99 10:18a Daveb
125 * Fixed incorrect CD checking problem on standalone server.
127 * 196 10/13/99 9:22a Daveb
128 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
129 * related to movies. Fixed launcher spawning from PXO screen.
131 * 195 10/06/99 11:05a Jefff
132 * new oem upsell 3 hotspot coords
134 * 194 10/06/99 10:31a Jefff
137 * 193 10/01/99 9:10a Daveb
140 * 192 9/15/99 4:57a Dave
141 * Updated ships.tbl checksum
143 * 191 9/15/99 3:58a Dave
144 * Removed framerate warning at all times.
146 * 190 9/15/99 3:16a Dave
147 * Remove mt-011.fs2 from the builtin mission list.
149 * 189 9/15/99 1:45a Dave
150 * Don't init joystick on standalone. Fixed campaign mode on standalone.
151 * Fixed no-score-report problem in TvT
153 * 188 9/14/99 6:08a Dave
154 * Updated (final) single, multi, and campaign list.
156 * 187 9/14/99 3:26a Dave
157 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
158 * respawn-too-early problem. Made a few crash points safe.
160 * 186 9/13/99 4:52p Dave
163 * 185 9/12/99 8:09p Dave
164 * Fixed problem where skip-training button would cause mission messages
165 * not to get paged out for the current mission.
167 * 184 9/10/99 11:53a Dave
168 * Shutdown graphics before sound to eliminate apparent lockups when
169 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
171 * 183 9/09/99 11:40p Dave
172 * Handle an Assert() in beam code. Added supernova sounds. Play the right
173 * 2 end movies properly, based upon what the player did in the mission.
175 * 182 9/08/99 10:29p Dave
176 * Make beam sound pausing and unpausing much safer.
178 * 181 9/08/99 10:01p Dave
179 * Make sure game won't run in a drive's root directory. Make sure
180 * standalone routes suqad war messages properly to the host.
182 * 180 9/08/99 3:22p Dave
183 * Updated builtin mission list.
185 * 179 9/08/99 12:01p Jefff
186 * fixed Game_builtin_mission_list typo on Training-2.fs2
188 * 178 9/08/99 9:48a Andsager
189 * Add force feedback for engine wash.
191 * 177 9/07/99 4:01p Dave
192 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
193 * does everything properly (setting up address when binding). Remove
194 * black rectangle background from UI_INPUTBOX.
196 * 176 9/13/99 2:40a Dave
197 * Comment in full 80 minute CD check for RELEASE_REAL builds.
199 * 175 9/06/99 6:38p Dave
200 * Improved CD detection code.
202 * 174 9/06/99 1:30a Dave
203 * Intermediate checkin. Started on enforcing CD-in-drive to play the
206 * 173 9/06/99 1:16a Dave
207 * Make sure the user sees the intro movie.
209 * 172 9/04/99 8:00p Dave
210 * Fixed up 1024 and 32 bit movie support.
212 * 171 9/03/99 1:32a Dave
213 * CD checking by act. Added support to play 2 cutscenes in a row
214 * seamlessly. Fixed super low level cfile bug related to files in the
215 * root directory of a CD. Added cheat code to set campaign mission # in
218 * 170 9/01/99 10:49p Dave
219 * Added nice SquadWar checkbox to the client join wait screen.
221 * 169 9/01/99 10:14a Dave
224 * 168 8/29/99 4:51p Dave
225 * Fixed damaged checkin.
227 * 167 8/29/99 4:18p Andsager
228 * New "burst" limit for friendly damage. Also credit more damage done
229 * against large friendly ships.
231 * 166 8/27/99 6:38p Alanl
232 * crush the blasted repeating messages bug
234 * 164 8/26/99 9:09p Dave
235 * Force framerate check in everything but a RELEASE_REAL build.
237 * 163 8/26/99 9:45a Dave
238 * First pass at easter eggs and cheats.
240 * 162 8/24/99 8:55p Dave
241 * Make sure nondimming pixels work properly in tech menu.
243 * 161 8/24/99 1:49a Dave
244 * Fixed client-side afterburner stuttering. Added checkbox for no version
245 * checking on PXO join. Made button info passing more friendly between
248 * 160 8/22/99 5:53p Dave
249 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
250 * instead of ship designations for multiplayer players.
252 * 159 8/22/99 1:19p Dave
253 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
254 * which d3d cards are detected.
256 * 158 8/20/99 2:09p Dave
257 * PXO banner cycling.
259 * 157 8/19/99 10:59a Dave
260 * Packet loss detection.
262 * 156 8/19/99 10:12a Alanl
263 * preload mission-specific messages on machines greater than 48MB
265 * 155 8/16/99 4:04p Dave
266 * Big honking checkin.
268 * 154 8/11/99 5:54p Dave
269 * Fixed collision problem. Fixed standalone ghost problem.
271 * 153 8/10/99 7:59p Jefff
274 * 152 8/10/99 6:54p Dave
275 * Mad optimizations. Added paging to the nebula effect.
277 * 151 8/10/99 3:44p Jefff
278 * loads Intelligence information on startup
280 * 150 8/09/99 3:47p Dave
281 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
282 * non-nebula missions.
284 * 149 8/09/99 2:21p Andsager
285 * Fix patching from multiplayer direct to launcher update tab.
287 * 148 8/09/99 10:36a Dave
288 * Version info for game.
290 * 147 8/06/99 9:46p Dave
291 * Hopefully final changes for the demo.
293 * 146 8/06/99 3:34p Andsager
294 * Make title version info "(D)" -> "D" show up nicely
296 * 145 8/06/99 2:59p Adamp
297 * Fixed NT launcher/update problem.
299 * 144 8/06/99 1:52p Dave
300 * Bumped up MAX_BITMAPS for the demo.
302 * 143 8/06/99 12:17p Andsager
303 * Demo: down to just 1 demo dog
305 * 142 8/05/99 9:39p Dave
306 * Yet another new checksum.
308 * 141 8/05/99 6:19p Dave
309 * New demo checksums.
311 * 140 8/05/99 5:31p Andsager
312 * Up demo version 1.01
314 * 139 8/05/99 4:22p Andsager
315 * No time limit on upsell screens. Reverse order of display of upsell
318 * 138 8/05/99 4:17p Dave
319 * Tweaks to client interpolation.
321 * 137 8/05/99 3:52p Danw
323 * 136 8/05/99 3:01p Danw
325 * 135 8/05/99 2:43a Anoop
326 * removed duplicate definition.
328 * 134 8/05/99 2:13a Dave
331 * 133 8/05/99 2:05a Dave
334 * 132 8/05/99 1:22a Andsager
337 * 131 8/04/99 9:51p Andsager
338 * Add title screen to demo
340 * 130 8/04/99 6:47p Jefff
341 * fixed link error resulting from #ifdefs
343 * 129 8/04/99 6:26p Dave
344 * Updated ship tbl checksum.
346 * 128 8/04/99 5:40p Andsager
347 * Add multiple demo dogs
349 * 127 8/04/99 5:36p Andsager
350 * Show upsell screens at end of demo campaign before returning to main
353 * 126 8/04/99 11:42a Danw
354 * tone down EAX reverb
356 * 125 8/04/99 11:23a Dave
357 * Updated demo checksums.
359 * 124 8/03/99 11:02p Dave
360 * Maybe fixed sync problems in multiplayer.
362 * 123 8/03/99 6:21p Jefff
365 * 122 8/03/99 3:44p Andsager
366 * Launch laucher if trying to run FS without first having configured
369 * 121 8/03/99 12:45p Dave
372 * 120 8/02/99 9:13p Dave
375 * 119 7/30/99 10:31p Dave
376 * Added comm menu to the configurable hud files.
378 * 118 7/30/99 5:17p Andsager
379 * first fs2demo checksums
381 * 117 7/29/99 3:09p Anoop
383 * 116 7/29/99 12:05a Dave
384 * Nebula speed optimizations.
386 * 115 7/27/99 8:59a Andsager
387 * Make major, minor version consistent for all builds. Only show major
388 * and minor for launcher update window.
390 * 114 7/26/99 5:50p Dave
391 * Revised ingame join. Better? We'll see....
393 * 113 7/26/99 5:27p Andsager
394 * Add training mission as builtin to demo build
396 * 112 7/24/99 1:54p Dave
397 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
400 * 111 7/22/99 4:00p Dave
401 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
403 * 110 7/21/99 8:10p Dave
404 * First run of supernova effect.
406 * 109 7/20/99 1:49p Dave
407 * Peter Drake build. Fixed some release build warnings.
409 * 108 7/19/99 2:26p Andsager
410 * set demo multiplayer missions
412 * 107 7/18/99 5:19p Dave
413 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
415 * 106 7/16/99 1:50p Dave
416 * 8 bit aabitmaps. yay.
418 * 105 7/15/99 3:07p Dave
419 * 32 bit detection support. Mouse coord commandline.
421 * 104 7/15/99 2:13p Dave
422 * Added 32 bit detection.
424 * 103 7/15/99 9:20a Andsager
425 * FS2_DEMO initial checkin
427 * 102 7/14/99 11:02a Dave
428 * Skill level default back to easy. Blech.
430 * 101 7/09/99 5:54p Dave
431 * Seperated cruiser types into individual types. Added tons of new
432 * briefing icons. Campaign screen.
434 * 100 7/08/99 4:43p Andsager
435 * New check for sparky_hi and print if not found.
437 * 99 7/08/99 10:53a Dave
438 * New multiplayer interpolation scheme. Not 100% done yet, but still
439 * better than the old way.
441 * 98 7/06/99 4:24p Dave
442 * Mid-level checkin. Starting on some potentially cool multiplayer
445 * 97 7/06/99 3:35p Andsager
446 * Allow movie to play before red alert mission.
448 * 96 7/03/99 5:50p Dave
449 * Make rotated bitmaps draw properly in padlock views.
451 * 95 7/02/99 9:55p Dave
452 * Player engine wash sound.
454 * 94 7/02/99 4:30p Dave
455 * Much more sophisticated lightning support.
457 * 93 6/29/99 7:52p Dave
458 * Put in exception handling in FS2.
460 * 92 6/22/99 9:37p Dave
461 * Put in pof spewing.
463 * 91 6/16/99 4:06p Dave
464 * New pilot info popup. Added new draw-bitmap-as-poly function.
466 * 90 6/15/99 1:56p Andsager
467 * For release builds, allow start up in high res only with
470 * 89 6/15/99 9:34a Dave
471 * Fixed key checking in single threaded version of the stamp notification
474 * 88 6/09/99 2:55p Andsager
475 * Allow multiple asteroid subtypes (of large, medium, small) and follow
478 * 87 6/08/99 1:14a Dave
479 * Multi colored hud test.
481 * 86 6/04/99 9:52a Dave
482 * Fixed some rendering problems.
484 * 85 6/03/99 10:15p Dave
485 * Put in temporary main hall screen.
487 * 84 6/02/99 6:18p Dave
488 * Fixed TNT lockup problems! Wheeeee!
490 * 83 6/01/99 3:52p Dave
491 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
492 * dead popup, pxo find player popup, pxo private room popup.
494 * 82 5/26/99 1:28p Jasenw
495 * changed coords for loading ani
497 * 81 5/26/99 11:46a Dave
498 * Added ship-blasting lighting and made the randomization of lighting
499 * much more customizable.
501 * 80 5/24/99 5:45p Dave
502 * Added detail levels to the nebula, with a decent speedup. Split nebula
503 * lightning into its own section.
521 #include "systemvars.h"
526 #include "starfield.h"
527 #include "lighting.h"
532 #include "fireballs.h"
536 #include "floating.h"
537 #include "gamesequence.h"
539 #include "optionsmenu.h"
540 #include "playermenu.h"
541 #include "trainingmenu.h"
542 #include "techmenu.h"
545 #include "hudmessage.h"
547 #include "missiongoals.h"
548 #include "missionparse.h"
553 #include "multiutil.h"
554 #include "multimsgs.h"
558 #include "freespace.h"
559 #include "managepilot.h"
561 #include "contexthelp.h"
564 #include "missionbrief.h"
565 #include "missiondebrief.h"
567 #include "missionshipchoice.h"
569 #include "hudconfig.h"
570 #include "controlsconfig.h"
571 #include "missionmessage.h"
572 #include "missiontraining.h"
574 #include "hudtarget.h"
576 #include "eventmusic.h"
577 #include "animplay.h"
578 #include "missionweaponchoice.h"
579 #include "missionlog.h"
580 #include "audiostr.h"
582 #include "missioncampaign.h"
584 #include "missionhotkey.h"
585 #include "objectsnd.h"
586 #include "cmeasure.h"
588 #include "linklist.h"
589 #include "shockwave.h"
590 #include "afterburner.h"
595 #include "stand_gui.h"
596 #include "pcxutils.h"
597 #include "hudtargetbox.h"
598 #include "multi_xfer.h"
599 #include "hudescort.h"
600 #include "multiutil.h"
603 #include "multiteamselect.h"
606 #include "readyroom.h"
607 #include "mainhallmenu.h"
608 #include "multilag.h"
610 #include "particle.h"
612 #include "multi_ingame.h"
613 #include "snazzyui.h"
614 #include "asteroid.h"
615 #include "popupdead.h"
616 #include "multi_voice.h"
617 #include "missioncmdbrief.h"
618 #include "redalert.h"
619 #include "gameplayhelp.h"
620 #include "multilag.h"
621 #include "staticrand.h"
622 #include "multi_pmsg.h"
623 #include "levelpaging.h"
624 #include "observer.h"
625 #include "multi_pause.h"
626 #include "multi_endgame.h"
627 #include "cutscenes.h"
628 #include "multi_respawn.h"
630 #include "multi_obj.h"
631 #include "multi_log.h"
633 #include "localize.h"
634 #include "osregistry.h"
635 #include "barracks.h"
636 #include "missionpause.h"
638 #include "alphacolors.h"
639 #include "objcollide.h"
642 #include "neblightning.h"
643 #include "shipcontrails.h"
646 #include "multi_dogfight.h"
647 #include "multi_rate.h"
648 #include "muzzleflash.h"
652 #include "mainhalltemp.h"
653 #include "exceptionhandler.h"
657 #include "supernova.h"
658 #include "hudshield.h"
659 // #include "names.h"
661 #include "missionloopbrief.h"
665 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
671 // 1.00.04 5/26/98 MWA -- going final (12 pm)
672 // 1.00.03 5/26/98 MWA -- going final (3 am)
673 // 1.00.02 5/25/98 MWA -- going final
674 // 1.00.01 5/25/98 MWA -- going final
675 // 0.90 5/21/98 MWA -- getting ready for final.
676 // 0.10 4/9/98. Set by MK.
678 // Demo version: (obsolete since DEMO codebase split from tree)
679 // 0.03 4/10/98 AL. Interplay rev
680 // 0.02 4/8/98 MK. Increased when this system was modified.
681 // 0.01 4/7/98? AL. First release to Interplay QA.
684 // 1.00 5/28/98 AL. First release to Interplay QA.
686 void game_level_init(int seed = -1);
687 void game_post_level_init();
688 void game_do_frame();
689 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
690 void game_reset_time();
691 void game_show_framerate(); // draws framerate in lower right corner
693 int Game_no_clear = 0;
695 int Pofview_running = 0;
696 int Nebedit_running = 0;
698 typedef struct big_expl_flash {
699 float max_flash_intensity; // max intensity
700 float cur_flash_intensity; // cur intensity
701 int flash_start; // start time
704 #define FRAME_FILTER 16
706 #define DEFAULT_SKILL_LEVEL 1
707 int Game_skill_level = DEFAULT_SKILL_LEVEL;
709 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
710 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
712 #define EXE_FNAME ("fs2.exe")
713 #define LAUNCHER_FNAME ("freespace2.exe")
715 // JAS: Code for warphole camera.
716 // Needs to be cleaned up.
717 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
718 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
719 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
720 matrix Camera_orient = IDENTITY_MATRIX;
721 float Camera_damping = 1.0f;
722 float Camera_time = 0.0f;
723 float Warpout_time = 0.0f;
724 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
725 int Warpout_sound = -1;
727 int Use_joy_mouse = 0;
728 int Use_palette_flash = 1;
730 int Use_fullscreen_at_startup = 0;
732 int Show_area_effect = 0;
733 object *Last_view_target = NULL;
735 int dogfight_blown = 0;
738 float frametimes[FRAME_FILTER];
739 float frametotal = 0.0f;
743 int Show_framerate = 0;
745 int Show_framerate = 1;
748 int Framerate_cap = 120;
751 int Show_target_debug_info = 0;
752 int Show_target_weapons = 0;
756 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
759 int Debug_octant = -1;
761 fix Game_time_compression = F1_0;
763 // if the ships.tbl the player has is valid
764 int Game_ships_tbl_valid = 0;
766 // if the weapons.tbl the player has is valid
767 int Game_weapons_tbl_valid = 0;
771 extern int Player_attacking_enabled;
775 int Pre_player_entry;
777 int Fred_running = 0;
778 char Game_current_mission_filename[MAX_FILENAME_LEN];
779 int game_single_step = 0;
780 int last_single_step=0;
782 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
783 extern int MSG_WINDOW_Y_START;
784 extern int MSG_WINDOW_HEIGHT;
786 int game_zbuffer = 1;
787 //static int Game_music_paused;
788 static int Game_paused;
792 #define EXPIRE_BAD_CHECKSUM 1
793 #define EXPIRE_BAD_TIME 2
795 extern void ssm_init();
796 extern void ssm_level_init();
797 extern void ssm_process();
799 // static variable to contain the time this version was built
800 // commented out for now until
801 // I figure out how to get the username into the file
802 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
804 // defines and variables used for dumping frame for making trailers.
806 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
807 int Debug_dump_trigger = 0;
808 int Debug_dump_frame_count;
809 int Debug_dump_frame_num = 0;
810 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
813 // amount of time to wait after the player has died before we display the death died popup
814 #define PLAYER_DIED_POPUP_WAIT 2500
815 int Player_died_popup_wait = -1;
816 int Player_multi_died_check = -1;
818 // builtin mission list stuff
820 int Game_builtin_mission_count = 6;
821 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
822 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
823 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
824 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
825 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
826 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
827 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
829 #elif defined(PD_BUILD)
830 int Game_builtin_mission_count = 4;
831 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
832 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
833 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
834 { "sm1-01", (FSB_FROM_VOLITION), "" },
835 { "sm1-05", (FSB_FROM_VOLITION), "" },
837 #elif defined(MULTIPLAYER_BETA)
838 int Game_builtin_mission_count = 17;
839 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
841 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
845 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
846 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
847 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
848 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
849 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
852 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
854 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
855 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
856 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
857 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
859 #elif defined(OEM_BUILD)
860 int Game_builtin_mission_count = 17;
861 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
862 // oem version - act 1 only
863 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
866 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
869 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
870 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
871 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
872 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
873 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
874 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
875 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
876 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
877 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
878 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
879 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
880 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
881 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
884 int Game_builtin_mission_count = 92;
885 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
886 // single player campaign
887 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
890 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
896 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
899 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
900 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
901 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
902 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
903 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
904 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
905 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
906 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
907 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
908 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
911 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
912 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
925 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
926 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
927 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
928 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
929 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
930 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
931 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
932 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
933 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
934 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
936 // multiplayer missions
939 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
984 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
985 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
987 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
988 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
989 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
992 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
993 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
994 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
995 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
996 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
1001 // Internal function prototypes
1002 void game_maybe_draw_mouse(float frametime);
1003 void init_animating_pointer();
1004 void load_animating_pointer(char *filename, int dx, int dy);
1005 void unload_animating_pointer();
1006 void game_do_training_checks();
1007 void game_shutdown(void);
1008 void game_show_event_debug(float frametime);
1009 void game_event_debug_init();
1011 void demo_upsell_show_screens();
1012 void game_start_subspace_ambient_sound();
1013 void game_stop_subspace_ambient_sound();
1014 void verify_ships_tbl();
1015 void verify_weapons_tbl();
1016 void display_title_screen();
1018 // loading background filenames
1019 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1020 "LoadingBG", // GR_640
1021 "2_LoadingBG" // GR_1024
1025 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1026 "Loading.ani", // GR_640
1027 "2_Loading.ani" // GR_1024
1030 #if defined(FS2_DEMO)
1031 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1035 #elif defined(OEM_BUILD)
1036 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1043 char Game_CDROM_dir[MAX_PATH_LEN];
1046 // How much RAM is on this machine. Set in WinMain
1047 uint Freespace_total_ram = 0;
1050 float Game_flash_red = 0.0f;
1051 float Game_flash_green = 0.0f;
1052 float Game_flash_blue = 0.0f;
1053 float Sun_spot = 0.0f;
1054 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1056 // game shudder stuff (in ms)
1057 int Game_shudder_time = -1;
1058 int Game_shudder_total = 0;
1059 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1062 sound_env Game_sound_env;
1063 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1064 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1066 int Game_sound_env_update_timestamp;
1068 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1071 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1073 fs_builtin_mission *game_find_builtin_mission(char *filename)
1077 // look through all existing builtin missions
1078 for(idx=0; idx<Game_builtin_mission_count; idx++){
1079 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1080 return &Game_builtin_mission_list[idx];
1088 int game_get_default_skill_level()
1090 return DEFAULT_SKILL_LEVEL;
1094 void game_flash_reset()
1096 Game_flash_red = 0.0f;
1097 Game_flash_green = 0.0f;
1098 Game_flash_blue = 0.0f;
1100 Big_expl_flash.max_flash_intensity = 0.0f;
1101 Big_expl_flash.cur_flash_intensity = 0.0f;
1102 Big_expl_flash.flash_start = 0;
1105 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1106 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1108 void game_framerate_check_init()
1110 // zero critical time
1111 Gf_critical_time = 0.0f;
1114 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1115 // if this is a glide card
1116 if(gr_screen.mode == GR_GLIDE){
1118 extern GrHwConfiguration hwconfig;
1121 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1122 Gf_critical = 15.0f;
1126 Gf_critical = 10.0f;
1131 Gf_critical = 15.0f;
1134 // d3d. only care about good cards here I guess (TNT)
1136 Gf_critical = 15.0f;
1139 // if this is a glide card
1140 if(gr_screen.mode == GR_GLIDE){
1142 extern GrHwConfiguration hwconfig;
1145 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1146 Gf_critical = 25.0f;
1150 Gf_critical = 20.0f;
1155 Gf_critical = 25.0f;
1158 // d3d. only care about good cards here I guess (TNT)
1160 Gf_critical = 25.0f;
1165 extern float Framerate;
1166 void game_framerate_check()
1170 // if the current framerate is above the critical level, add frametime
1171 if(Framerate >= Gf_critical){
1172 Gf_critical_time += flFrametime;
1175 if(!Show_framerate){
1179 // display if we're above the critical framerate
1180 if(Framerate < Gf_critical){
1181 gr_set_color_fast(&Color_bright_red);
1182 gr_string(200, y_start, "Framerate warning");
1187 // display our current pct of good frametime
1188 if(f2fl(Missiontime) >= 0.0f){
1189 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1192 gr_set_color_fast(&Color_bright_green);
1194 gr_set_color_fast(&Color_bright_red);
1197 gr_printf(200, y_start, "%d%%", (int)pct);
1204 // Adds a flash effect. These can be positive or negative.
1205 // The range will get capped at around -1 to 1, so stick
1206 // with a range like that.
1207 void game_flash( float r, float g, float b )
1209 Game_flash_red += r;
1210 Game_flash_green += g;
1211 Game_flash_blue += b;
1213 if ( Game_flash_red < -1.0f ) {
1214 Game_flash_red = -1.0f;
1215 } else if ( Game_flash_red > 1.0f ) {
1216 Game_flash_red = 1.0f;
1219 if ( Game_flash_green < -1.0f ) {
1220 Game_flash_green = -1.0f;
1221 } else if ( Game_flash_green > 1.0f ) {
1222 Game_flash_green = 1.0f;
1225 if ( Game_flash_blue < -1.0f ) {
1226 Game_flash_blue = -1.0f;
1227 } else if ( Game_flash_blue > 1.0f ) {
1228 Game_flash_blue = 1.0f;
1233 // Adds a flash for Big Ship explosions
1234 // cap range from 0 to 1
1235 void big_explosion_flash(float flash)
1237 Big_expl_flash.flash_start = timestamp(1);
1241 } else if (flash < 0.0f) {
1245 Big_expl_flash.max_flash_intensity = flash;
1246 Big_expl_flash.cur_flash_intensity = 0.0f;
1249 // Amount to diminish palette towards normal, per second.
1250 #define DIMINISH_RATE 0.75f
1251 #define SUN_DIMINISH_RATE 6.00f
1255 float sn_glare_scale = 1.7f;
1258 dc_get_arg(ARG_FLOAT);
1259 sn_glare_scale = Dc_arg_float;
1262 float Supernova_last_glare = 0.0f;
1263 void game_sunspot_process(float frametime)
1267 float Sun_spot_goal = 0.0f;
1270 sn_stage = supernova_active();
1272 // sunspot differently based on supernova stage
1274 // approaching. player still in control
1277 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1280 light_get_global_dir(&light_dir, 0);
1282 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1285 // scale it some more
1286 dot = dot * (0.5f + (pct * 0.5f));
1289 Sun_spot_goal += (dot * sn_glare_scale);
1292 // draw the sun glow
1293 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1294 // draw the glow for this sun
1295 stars_draw_sun_glow(0);
1298 Supernova_last_glare = Sun_spot_goal;
1301 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1304 Sun_spot_goal = 0.9f;
1305 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1307 if(Sun_spot_goal > 1.0f){
1308 Sun_spot_goal = 1.0f;
1311 Sun_spot_goal *= sn_glare_scale;
1312 Supernova_last_glare = Sun_spot_goal;
1315 // fade to white. display dead popup
1318 Supernova_last_glare += (2.0f * flFrametime);
1319 if(Supernova_last_glare > 2.0f){
1320 Supernova_last_glare = 2.0f;
1323 Sun_spot_goal = Supernova_last_glare;
1330 // check sunspots for all suns
1331 n_lights = light_get_global_count();
1334 for(idx=0; idx<n_lights; idx++){
1335 //(vector *eye_pos, matrix *eye_orient)
1336 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1339 light_get_global_dir(&light_dir, idx);
1341 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1343 Sun_spot_goal += (float)pow(dot,85.0f);
1345 // draw the glow for this sun
1346 stars_draw_sun_glow(idx);
1348 Sun_spot_goal = 0.0f;
1354 Sun_spot_goal = 0.0f;
1358 float dec_amount = frametime*SUN_DIMINISH_RATE;
1360 if ( Sun_spot < Sun_spot_goal ) {
1361 Sun_spot += dec_amount;
1362 if ( Sun_spot > Sun_spot_goal ) {
1363 Sun_spot = Sun_spot_goal;
1365 } else if ( Sun_spot > Sun_spot_goal ) {
1366 Sun_spot -= dec_amount;
1367 if ( Sun_spot < Sun_spot_goal ) {
1368 Sun_spot = Sun_spot_goal;
1374 // Call once a frame to diminish the
1375 // flash effect to 0.
1376 void game_flash_diminish(float frametime)
1378 float dec_amount = frametime*DIMINISH_RATE;
1380 if ( Game_flash_red > 0.0f ) {
1381 Game_flash_red -= dec_amount;
1382 if ( Game_flash_red < 0.0f )
1383 Game_flash_red = 0.0f;
1385 Game_flash_red += dec_amount;
1386 if ( Game_flash_red > 0.0f )
1387 Game_flash_red = 0.0f;
1390 if ( Game_flash_green > 0.0f ) {
1391 Game_flash_green -= dec_amount;
1392 if ( Game_flash_green < 0.0f )
1393 Game_flash_green = 0.0f;
1395 Game_flash_green += dec_amount;
1396 if ( Game_flash_green > 0.0f )
1397 Game_flash_green = 0.0f;
1400 if ( Game_flash_blue > 0.0f ) {
1401 Game_flash_blue -= dec_amount;
1402 if ( Game_flash_blue < 0.0f )
1403 Game_flash_blue = 0.0f;
1405 Game_flash_blue += dec_amount;
1406 if ( Game_flash_blue > 0.0f )
1407 Game_flash_blue = 0.0f;
1410 // update big_explosion_cur_flash
1411 #define TIME_UP 1500
1412 #define TIME_DOWN 2500
1413 int duration = TIME_UP + TIME_DOWN;
1414 int time = timestamp_until(Big_expl_flash.flash_start);
1415 if (time > -duration) {
1417 if (time < TIME_UP) {
1418 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1421 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1425 if ( Use_palette_flash ) {
1427 // static int or=0, og=0, ob=0;
1429 // Change the 200 to change the color range of colors.
1430 r = fl2i( Game_flash_red*128.0f );
1431 g = fl2i( Game_flash_green*128.0f );
1432 b = fl2i( Game_flash_blue*128.0f );
1434 if ( Sun_spot > 0.0f ) {
1435 r += fl2i(Sun_spot*128.0f);
1436 g += fl2i(Sun_spot*128.0f);
1437 b += fl2i(Sun_spot*128.0f);
1440 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1441 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1442 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1443 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1446 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1447 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1448 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1450 if ( (r!=0) || (g!=0) || (b!=0) ) {
1451 gr_flash( r, g, b );
1453 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1464 void game_level_close()
1466 // De-Initialize the game subsystems
1467 message_mission_shutdown();
1468 event_music_level_close();
1469 game_stop_looped_sounds();
1471 obj_snd_level_close(); // uninit object-linked persistant sounds
1472 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1473 anim_level_close(); // stop and clean up any anim instances
1474 shockwave_level_close();
1475 fireball_level_close();
1477 mission_event_shutdown();
1478 asteroid_level_close();
1479 model_cache_reset(); // Reset/free all the model caching stuff
1480 flak_level_close(); // unload flak stuff
1481 neb2_level_close(); // shutdown gaseous nebula stuff
1484 mflash_level_close();
1486 audiostream_unpause_all();
1491 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1492 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1493 void game_level_init(int seed)
1495 // seed the random number generator
1497 // if no seed was passed, seed the generator either from the time value, or from the
1498 // netgame security flags -- ensures that all players in multiplayer game will have the
1499 // same randon number sequence (with static rand functions)
1500 if ( Game_mode & GM_NORMAL ) {
1501 Game_level_seed = time(NULL);
1503 Game_level_seed = Netgame.security;
1506 // mwa 9/17/98 -- maybe this assert isn't needed????
1507 Assert( !(Game_mode & GM_MULTIPLAYER) );
1508 Game_level_seed = seed;
1510 srand( Game_level_seed );
1512 // semirand function needs to get re-initted every time in multiplayer
1513 if ( Game_mode & GM_MULTIPLAYER ){
1519 Key_normal_game = (Game_mode & GM_NORMAL);
1522 Game_shudder_time = -1;
1524 // Initialize the game subsystems
1525 // timestamp_reset(); // Must be inited before everything else
1527 game_reset_time(); // resets time, and resets saved time too
1529 obj_init(); // Must be inited before the other systems
1530 model_free_all(); // Free all existing models
1531 mission_brief_common_init(); // Free all existing briefing/debriefing text
1532 weapon_level_init();
1533 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1535 player_level_init();
1536 shipfx_flash_init(); // Init the ship gun flash system.
1537 game_flash_reset(); // Reset the flash effect
1538 particle_init(); // Reset the particle system
1542 shield_hit_init(); // Initialize system for showing shield hits
1543 radar_mission_init();
1544 mission_init_goals();
1547 obj_snd_level_init(); // init object-linked persistant sounds
1549 shockwave_level_init();
1550 afterburner_level_init();
1551 scoring_level_init( &Player->stats );
1553 asteroid_level_init();
1554 control_config_clear_used_status();
1555 collide_ship_ship_sounds_init();
1557 Pre_player_entry = 1; // Means the player has not yet entered.
1558 Entry_delay_time = 0; // Could get overwritten in mission read.
1559 fireball_preload(); // page in warphole bitmaps
1561 flak_level_init(); // initialize flak - bitmaps, etc
1562 ct_level_init(); // initialize ships contrails, etc
1563 awacs_level_init(); // initialize AWACS
1564 beam_level_init(); // initialize beam weapons
1565 mflash_level_init();
1567 supernova_level_init();
1569 // multiplayer dogfight hack
1572 shipfx_engine_wash_level_init();
1576 Last_view_target = NULL;
1581 // campaign wasn't ended
1582 Campaign_ended_in_mission = 0;
1585 // called when a mission is over -- does server specific stuff.
1586 void freespace_stop_mission()
1589 Game_mode &= ~GM_IN_MISSION;
1592 // called at frame interval to process networking stuff
1593 void game_do_networking()
1595 Assert( Net_player != NULL );
1596 if (!(Game_mode & GM_MULTIPLAYER)){
1600 // see if this player should be reading/writing data. Bit is set when at join
1601 // screen onward until quits back to main menu.
1602 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1606 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1609 multi_pause_do_frame();
1614 // Loads the best palette for this level, based
1615 // on nebula color and hud color. You could just call palette_load_table with
1616 // the appropriate filename, but who wants to do that.
1617 void game_load_palette()
1619 char palette_filename[1024];
1621 // We only use 3 hud colors right now
1622 // Assert( HUD_config.color >= 0 );
1623 // Assert( HUD_config.color <= 2 );
1625 Assert( Mission_palette >= 0 );
1626 Assert( Mission_palette <= 98 );
1628 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1629 strcpy( palette_filename, NOX("gamepalette-subspace") );
1631 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1634 mprintf(( "Loading palette %s\n", palette_filename ));
1636 // palette_load_table(palette_filename);
1639 void game_post_level_init()
1641 // Stuff which gets called after mission is loaded. Because player isn't created until
1642 // after mission loads, some things must get initted after the level loads
1644 model_level_post_init();
1647 hud_setup_escort_list();
1648 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1654 game_event_debug_init();
1657 training_mission_init();
1658 asteroid_create_all();
1660 game_framerate_check_init();
1664 // An estimate as to how high the count passed to game_loading_callback will go.
1665 // This is just a guess, it seems to always be about the same. The count is
1666 // proportional to the code being executed, not the time, so this works good
1667 // for a bar, assuming the code does about the same thing each time you
1668 // load a level. You can find this value by looking at the return value
1669 // of game_busy_callback(NULL), which I conveniently print out to the
1670 // debug output window with the '=== ENDING LOAD ==' stuff.
1671 //#define COUNT_ESTIMATE 3706
1672 #define COUNT_ESTIMATE 1111
1674 int Game_loading_callback_inited = 0;
1676 int Game_loading_background = -1;
1677 anim * Game_loading_ani = NULL;
1678 anim_instance *Game_loading_ani_instance;
1679 int Game_loading_frame=-1;
1681 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1690 // This gets called 10x per second and count is the number of times
1691 // game_busy() has been called since the current callback function
1693 void game_loading_callback(int count)
1695 game_do_networking();
1697 Assert( Game_loading_callback_inited==1 );
1698 Assert( Game_loading_ani != NULL );
1700 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1701 if ( framenum > Game_loading_ani->total_frames-1 ) {
1702 framenum = Game_loading_ani->total_frames-1;
1703 } else if ( framenum < 0 ) {
1708 while ( Game_loading_frame < framenum ) {
1709 Game_loading_frame++;
1710 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1714 if ( cbitmap > -1 ) {
1715 if ( Game_loading_background > -1 ) {
1716 gr_set_bitmap( Game_loading_background );
1720 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1721 gr_set_bitmap( cbitmap );
1722 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1724 bm_release(cbitmap);
1730 void game_loading_callback_init()
1732 Assert( Game_loading_callback_inited==0 );
1734 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1735 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1738 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1739 Assert( Game_loading_ani != NULL );
1740 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1741 Assert( Game_loading_ani_instance != NULL );
1742 Game_loading_frame = -1;
1744 Game_loading_callback_inited = 1;
1746 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1751 void game_loading_callback_close()
1753 Assert( Game_loading_callback_inited==1 );
1755 // Make sure bar shows all the way over.
1756 game_loading_callback(COUNT_ESTIMATE);
1758 int real_count = game_busy_callback( NULL );
1761 Game_loading_callback_inited = 0;
1764 mprintf(( "=================== ENDING LOAD ================\n" ));
1765 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1766 mprintf(( "================================================\n" ));
1768 // to remove warnings in release build
1772 free_anim_instance(Game_loading_ani_instance);
1773 Game_loading_ani_instance = NULL;
1774 anim_free(Game_loading_ani);
1775 Game_loading_ani = NULL;
1777 bm_release( Game_loading_background );
1778 common_free_interface_palette(); // restore game palette
1779 Game_loading_background = -1;
1781 gr_set_font( FONT1 );
1784 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1786 void game_maybe_update_sound_environment()
1788 // do nothing for now
1791 // Assign the sound environment for the game, based on the current mission
1793 void game_assign_sound_environment()
1796 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1797 Game_sound_env.id = SND_ENV_DRUGGED;
1798 Game_sound_env.volume = 0.800f;
1799 Game_sound_env.damping = 1.188f;
1800 Game_sound_env.decay = 6.392f;
1802 } else if (Num_asteroids > 30) {
1803 Game_sound_env.id = SND_ENV_AUDITORIUM;
1804 Game_sound_env.volume = 0.603f;
1805 Game_sound_env.damping = 0.5f;
1806 Game_sound_env.decay = 4.279f;
1809 Game_sound_env = Game_default_sound_env;
1813 Game_sound_env = Game_default_sound_env;
1814 Game_sound_env_update_timestamp = timestamp(1);
1817 // function which gets called before actually entering the mission. It is broken down into a funciton
1818 // since it will get called in one place from a single player game and from another place for
1819 // a multiplayer game
1820 void freespace_mission_load_stuff()
1822 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1823 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1824 if(!(Game_mode & GM_STANDALONE_SERVER)){
1826 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1828 game_loading_callback_init();
1830 event_music_level_init(); // preloads the first 2 seconds for each event music track
1833 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1836 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1839 ship_assign_sound_all(); // assign engine sounds to ships
1840 game_assign_sound_environment(); // assign the sound environment for this mission
1843 // call function in missionparse.cpp to fixup player/ai stuff.
1844 mission_parse_fixup_players();
1847 // Load in all the bitmaps for this level
1852 game_loading_callback_close();
1854 // the only thing we need to call on the standalone for now.
1856 // call function in missionparse.cpp to fixup player/ai stuff.
1857 mission_parse_fixup_players();
1859 // Load in all the bitmaps for this level
1865 uint load_mission_load;
1866 uint load_post_level_init;
1867 uint load_mission_stuff;
1869 // tells the server to load the mission and initialize structures
1870 int game_start_mission()
1872 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1874 load_gl_init = time(NULL);
1876 load_gl_init = time(NULL) - load_gl_init;
1878 if (Game_mode & GM_MULTIPLAYER) {
1879 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1881 // clear multiplayer stats
1882 init_multiplayer_stats();
1885 load_mission_load = time(NULL);
1886 if (mission_load()) {
1887 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1888 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1889 gameseq_post_event(GS_EVENT_MAIN_MENU);
1891 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1896 load_mission_load = time(NULL) - load_mission_load;
1898 // If this is a red alert mission in campaign mode, bash wingman status
1899 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1900 red_alert_bash_wingman_status();
1903 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1904 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1905 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1906 // game_load_palette();
1909 load_post_level_init = time(NULL);
1910 game_post_level_init();
1911 load_post_level_init = time(NULL) - load_post_level_init;
1915 void Do_model_timings_test();
1916 Do_model_timings_test();
1920 load_mission_stuff = time(NULL);
1921 freespace_mission_load_stuff();
1922 load_mission_stuff = time(NULL) - load_mission_stuff;
1927 int Interface_framerate = 0;
1930 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1931 DCF_BOOL( show_framerate, Show_framerate )
1932 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1933 DCF_BOOL( show_target_weapons, Show_target_weapons )
1934 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1935 DCF_BOOL( sound, Sound_enabled )
1936 DCF_BOOL( zbuffer, game_zbuffer )
1937 DCF_BOOL( shield_system, New_shield_system )
1938 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1939 DCF_BOOL( player_attacking, Player_attacking_enabled )
1940 DCF_BOOL( show_waypoints, Show_waypoints )
1941 DCF_BOOL( show_area_effect, Show_area_effect )
1942 DCF_BOOL( show_net_stats, Show_net_stats )
1943 DCF_BOOL( log, Log_debug_output_to_file )
1944 DCF_BOOL( training_msg_method, Training_msg_method )
1945 DCF_BOOL( show_player_pos, Show_player_pos )
1946 DCF_BOOL(i_framerate, Interface_framerate )
1948 DCF(show_mem,"Toggles showing mem usage")
1951 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1952 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1953 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1954 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1960 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1962 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1963 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1967 DCF(show_cpu,"Toggles showing cpu usage")
1970 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1971 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1972 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1973 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1979 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1981 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1982 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1989 // AL 4-8-98: always allow players to display their framerate
1992 DCF_BOOL( show_framerate, Show_framerate )
1999 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
2002 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2003 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2004 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2005 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2007 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" );
2008 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2010 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2013 DCF(palette_flash,"Toggles palette flash effect on/off")
2016 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2017 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2018 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2019 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2021 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2022 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2025 int Use_low_mem = 0;
2027 DCF(low_mem,"Uses low memory settings regardless of RAM")
2030 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2031 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2032 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2033 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2035 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2036 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2038 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2044 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2047 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2048 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2049 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2050 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2052 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2053 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2054 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2058 int Framerate_delay = 0;
2060 float Freespace_gamma = 1.0f;
2062 DCF(gamma,"Sets Gamma factor")
2065 dc_get_arg(ARG_FLOAT|ARG_NONE);
2066 if ( Dc_arg_type & ARG_FLOAT ) {
2067 Freespace_gamma = Dc_arg_float;
2069 dc_printf( "Gamma reset to 1.0f\n" );
2070 Freespace_gamma = 1.0f;
2072 if ( Freespace_gamma < 0.1f ) {
2073 Freespace_gamma = 0.1f;
2074 } else if ( Freespace_gamma > 5.0f ) {
2075 Freespace_gamma = 5.0f;
2077 gr_set_gamma(Freespace_gamma);
2079 char tmp_gamma_string[32];
2080 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2081 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2085 dc_printf( "Usage: gamma <float>\n" );
2086 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2087 Dc_status = 0; // don't print status if help is printed. Too messy.
2091 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2100 Game_current_mission_filename[0] = 0;
2102 // seed the random number generator
2103 Game_init_seed = time(NULL);
2104 srand( Game_init_seed );
2106 Framerate_delay = 0;
2112 extern void bm_init();
2118 // Initialize the timer before the os
2126 GetCurrentDirectory(1024, whee);
2129 getcwd (whee, 1024);
2132 strcat(whee, EXE_FNAME);
2134 //Initialize the libraries
2135 s1 = timer_get_milliseconds();
2136 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2139 e1 = timer_get_milliseconds();
2141 // time a bunch of cfopens
2143 s2 = timer_get_milliseconds();
2145 for(int idx=0; idx<10000; idx++){
2146 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2151 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2153 e2 = timer_get_milliseconds();
2156 if (Is_standalone) {
2157 std_init_standalone();
2159 os_init( Osreg_class_name, Osreg_app_name );
2160 os_set_title(Osreg_title);
2163 // initialize localization module. Make sure this is down AFTER initialzing OS.
2164 // int t1 = timer_get_milliseconds();
2167 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2169 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2172 // verify that he has a valid weapons.tbl
2173 verify_weapons_tbl();
2175 // Output version numbers to registry for auto patching purposes
2176 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2177 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2178 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2180 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2181 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2182 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2185 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2189 Asteroids_enabled = 1;
2192 /////////////////////////////
2194 /////////////////////////////
2199 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2200 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2202 if (!stricmp(ptr, NOX("no sound"))) {
2203 Cmdline_freespace_no_sound = 1;
2205 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2207 } else if (!stricmp(ptr, NOX("EAX"))) {
2212 if (!Is_standalone) {
2213 snd_init(use_a3d, use_eax);
2215 /////////////////////////////
2217 /////////////////////////////
2219 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2222 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);
2224 // fire up the UpdateLauncher executable
2226 PROCESS_INFORMATION pi;
2228 memset( &si, 0, sizeof(STARTUPINFO) );
2231 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2232 NULL, // pointer to command line string
2233 NULL, // pointer to process security attributes
2234 NULL, // pointer to thread security attributes
2235 FALSE, // handle inheritance flag
2236 CREATE_DEFAULT_ERROR_MODE, // creation flags
2237 NULL, // pointer to new environment block
2238 NULL, // pointer to current directory name
2239 &si, // pointer to STARTUPINFO
2240 &pi // pointer to PROCESS_INFORMATION
2243 // If the Launcher could not be started up, let the user know
2245 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2254 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2256 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);
2264 // check for hi res pack file
2265 int has_sparky_hi = 0;
2267 // check if sparky_hi exists -- access mode 0 means does file exist
2270 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2273 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2276 // see if we've got 32 bit in the string
2277 if(strstr(ptr, "32 bit")){
2284 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2286 // always 640 for E3
2287 gr_init(GR_640, GR_GLIDE);
2289 // regular or hi-res ?
2291 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2293 if(strstr(ptr, NOX("(1024x768)"))){
2295 gr_init(GR_1024, GR_GLIDE);
2297 gr_init(GR_640, GR_GLIDE);
2300 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2302 // always 640 for E3
2304 gr_init(GR_640, GR_DIRECT3D, depth);
2306 // regular or hi-res ?
2308 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2310 if(strstr(ptr, NOX("(1024x768)"))){
2314 gr_init(GR_1024, GR_DIRECT3D, depth);
2318 gr_init(GR_640, GR_DIRECT3D, depth);
2324 if ( Use_fullscreen_at_startup && !Is_standalone) {
2325 gr_init(GR_640, GR_DIRECTDRAW);
2327 gr_init(GR_640, GR_SOFTWARE);
2330 if ( !Is_standalone ) {
2331 gr_init(GR_640, GR_DIRECTDRAW);
2333 gr_init(GR_640, GR_SOFTWARE);
2338 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2339 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2340 gr_init(GR_1024, GR_OPENGL);
2342 gr_init(GR_640, GR_OPENGL);
2346 gr_init(GR_640, GR_SOFTWARE);
2351 extern int Gr_inited;
2352 if(trying_d3d && !Gr_inited){
2354 extern char Device_init_error[512];
2355 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2364 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2365 Freespace_gamma = (float)atof(ptr);
2366 if ( Freespace_gamma == 0.0f ) {
2367 Freespace_gamma = 1.80f;
2368 } else if ( Freespace_gamma < 0.1f ) {
2369 Freespace_gamma = 0.1f;
2370 } else if ( Freespace_gamma > 5.0f ) {
2371 Freespace_gamma = 5.0f;
2373 char tmp_gamma_string[32];
2374 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2375 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2377 gr_set_gamma(Freespace_gamma);
2379 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2382 display_title_screen();
2386 // attempt to load up master tracker registry info (login and password)
2387 Multi_tracker_id = -1;
2389 // pxo login and password
2390 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2392 nprintf(("Network","Error reading in PXO login data\n"));
2393 strcpy(Multi_tracker_login,"");
2395 strcpy(Multi_tracker_login,ptr);
2397 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2399 nprintf(("Network","Error reading PXO password\n"));
2400 strcpy(Multi_tracker_passwd,"");
2402 strcpy(Multi_tracker_passwd,ptr);
2405 // pxo squad name and password
2406 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2408 nprintf(("Network","Error reading in PXO squad name\n"));
2409 strcpy(Multi_tracker_squad_name, "");
2411 strcpy(Multi_tracker_squad_name, ptr);
2414 // If less than 48MB of RAM, use low memory model.
2417 (Freespace_total_ram < 48*1024*1024) ||
2420 mprintf(( "Using normal memory settings...\n" ));
2421 bm_set_low_mem(1); // Use every other frame of bitmaps
2423 mprintf(( "Using high memory settings...\n" ));
2424 bm_set_low_mem(0); // Use all frames of bitmaps
2427 // load non-darkening pixel defs
2428 palman_load_pixels();
2430 // hud shield icon stuff
2431 hud_shield_game_init();
2433 control_config_common_init(); // sets up localization stuff in the control config
2439 gamesnd_parse_soundstbl();
2444 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2449 player_controls_init();
2452 //if(!Is_standalone){
2460 ship_init(); // read in ships.tbl
2462 mission_campaign_init(); // load in the default campaign
2464 // navmap_init(); // init the navigation map system
2465 context_help_init();
2466 techroom_intel_init(); // parse species.tbl, load intel info
2468 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2469 init_animating_pointer();
2471 mission_brief_common_init(); // Mark all the briefing structures as empty.
2472 gr_font_init(); // loads up all fonts
2474 neb2_init(); // fullneb stuff
2478 player_tips_init(); // helpful tips
2481 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2482 pilot_load_pic_list();
2483 pilot_load_squad_pic_list();
2485 load_animating_pointer(NOX("cursor"), 0, 0);
2487 // initialize alpha colors
2488 alpha_colors_init();
2491 // Game_music_paused = 0;
2498 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2499 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2501 mprintf(("cfile_init() took %d\n", e1 - s1));
2502 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2505 char transfer_text[128];
2507 float Start_time = 0.0f;
2509 float Framerate = 0.0f;
2511 float Timing_total = 0.0f;
2512 float Timing_render2 = 0.0f;
2513 float Timing_render3 = 0.0f;
2514 float Timing_flip = 0.0f;
2515 float Timing_clear = 0.0f;
2517 MONITOR(NumPolysDrawn);
2523 void game_get_framerate()
2525 char text[128] = "";
2527 if ( frame_int == -1 ) {
2529 for (i=0; i<FRAME_FILTER; i++ ) {
2530 frametimes[i] = 0.0f;
2535 frametotal -= frametimes[frame_int];
2536 frametotal += flFrametime;
2537 frametimes[frame_int] = flFrametime;
2538 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2540 if ( frametotal != 0.0 ) {
2541 if ( Framecount >= FRAME_FILTER )
2542 Framerate = FRAME_FILTER / frametotal;
2544 Framerate = Framecount / frametotal;
2545 sprintf( text, NOX("FPS: %.1f"), Framerate );
2547 sprintf( text, NOX("FPS: ?") );
2551 if (Show_framerate) {
2552 gr_set_color_fast(&HUD_color_debug);
2553 gr_string( 570, 2, text );
2557 void game_show_framerate()
2561 cur_time = f2fl(timer_get_approx_seconds());
2562 if (cur_time - Start_time > 30.0f) {
2563 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2564 Start_time += 1000.0f;
2567 //mprintf(( "%s\n", text ));
2570 if ( Debug_dump_frames )
2574 // possibly show control checking info
2575 control_check_indicate();
2577 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2578 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2579 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2580 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2583 if ( Show_cpu == 1 ) {
2588 dy = gr_get_font_height() + 1;
2590 gr_set_color_fast(&HUD_color_debug);
2594 extern int D3D_textures_in;
2595 extern int D3D_textures_in_frame;
2596 extern int Glide_textures_in;
2597 extern int Glide_textures_in_frame;
2598 extern int Glide_explosion_vram;
2599 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2601 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2603 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2607 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2609 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2611 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2613 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2615 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2620 extern int Num_pairs; // Number of object pairs that were checked.
2621 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2624 extern int Num_pairs_checked; // What percent of object pairs were checked.
2625 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2627 Num_pairs_checked = 0;
2631 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2634 if ( Timing_total > 0.01f ) {
2635 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2637 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2639 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2641 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2643 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2653 dy = gr_get_font_height() + 1;
2655 gr_set_color_fast(&HUD_color_debug);
2658 extern int TotalRam;
2659 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2664 extern int Model_ram;
2665 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2669 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2671 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2673 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2677 extern int D3D_textures_in;
2678 extern int Glide_textures_in;
2679 extern int Glide_textures_in_frame;
2680 extern int Glide_explosion_vram;
2681 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2683 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2685 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2692 if ( Show_player_pos ) {
2696 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));
2699 MONITOR_INC(NumPolys, modelstats_num_polys);
2700 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2701 MONITOR_INC(NumVerts, modelstats_num_verts );
2703 modelstats_num_polys = 0;
2704 modelstats_num_polys_drawn = 0;
2705 modelstats_num_verts = 0;
2706 modelstats_num_sortnorms = 0;
2710 void game_show_standalone_framerate()
2712 float frame_rate=30.0f;
2713 if ( frame_int == -1 ) {
2715 for (i=0; i<FRAME_FILTER; i++ ) {
2716 frametimes[i] = 0.0f;
2721 frametotal -= frametimes[frame_int];
2722 frametotal += flFrametime;
2723 frametimes[frame_int] = flFrametime;
2724 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2726 if ( frametotal != 0.0 ) {
2727 if ( Framecount >= FRAME_FILTER ){
2728 frame_rate = FRAME_FILTER / frametotal;
2730 frame_rate = Framecount / frametotal;
2733 std_set_standalone_fps(frame_rate);
2737 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2738 void game_show_time_left()
2742 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2743 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2744 // checking how much time is left
2746 if ( Mission_end_time == -1 ){
2750 diff = f2i(Mission_end_time - Missiontime);
2751 // be sure to bash to 0. diff could be negative on frame that we quit mission
2756 hud_set_default_color();
2757 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2760 //========================================================================================
2761 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2762 //========================================================================================
2766 DCF(ai_pause,"Pauses ai")
2769 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2770 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2771 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2772 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2775 obj_init_all_ships_physics();
2778 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2779 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2782 DCF(single_step,"Single steps the game")
2785 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2786 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2787 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2788 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2790 last_single_step = 0; // Make so single step waits a frame before stepping
2793 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2794 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2797 DCF_BOOL(physics_pause, physics_paused)
2798 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2799 DCF_BOOL(ai_firing, Ai_firing_enabled )
2801 // Create some simple aliases to these commands...
2802 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2803 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2804 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2805 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2806 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2809 //========================================================================================
2810 //========================================================================================
2813 void game_training_pause_do()
2817 key = game_check_key();
2819 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2826 void game_increase_skill_level()
2829 if (Game_skill_level >= NUM_SKILL_LEVELS){
2830 Game_skill_level = 0;
2834 int Player_died_time;
2836 int View_percent = 100;
2839 DCF(view, "Sets the percent of the 3d view to render.")
2842 dc_get_arg(ARG_INT);
2843 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2844 View_percent = Dc_arg_int;
2846 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2852 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2856 dc_printf("View is set to %d%%\n", View_percent );
2861 // Set the clip region for the 3d rendering window
2862 void game_set_view_clip()
2864 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2865 // Set the clip region for the letterbox "dead view"
2866 int yborder = gr_screen.max_h/4;
2868 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2869 // J.S. I've changed my ways!! See the new "no constants" code!!!
2870 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2872 // Set the clip region for normal view
2873 if ( View_percent >= 100 ) {
2876 int xborder, yborder;
2878 if ( View_percent < 5 ) {
2882 float fp = i2fl(View_percent)/100.0f;
2883 int fi = fl2i(fl_sqrt(fp)*100.0f);
2884 if ( fi > 100 ) fi=100;
2886 xborder = ( gr_screen.max_w*(100-fi) )/200;
2887 yborder = ( gr_screen.max_h*(100-fi) )/200;
2889 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2895 void show_debug_stuff()
2898 int laser_count = 0, missile_count = 0;
2900 for (i=0; i<MAX_OBJECTS; i++) {
2901 if (Objects[i].type == OBJ_WEAPON){
2902 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2904 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2910 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2913 extern int Tool_enabled;
2918 int tst_bitmap = -1;
2920 float tst_offset, tst_offset_total;
2923 void game_tst_frame_pre()
2931 g3_rotate_vertex(&v, &tst_pos);
2932 g3_project_vertex(&v);
2935 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2939 // big ship? always tst
2941 // within 3000 meters
2942 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2946 // within 300 meters
2947 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2954 void game_tst_frame()
2964 tst_time = time(NULL);
2966 // load the tst bitmap
2967 switch((int)frand_range(0.0f, 3.0)){
2969 tst_bitmap = bm_load("ig_jim");
2971 mprintf(("TST 0\n"));
2975 tst_bitmap = bm_load("ig_kan");
2977 mprintf(("TST 1\n"));
2981 tst_bitmap = bm_load("ig_jim");
2983 mprintf(("TST 2\n"));
2987 tst_bitmap = bm_load("ig_kan");
2989 mprintf(("TST 3\n"));
2998 // get the tst bitmap dimensions
3000 bm_get_info(tst_bitmap, &w, &h);
3003 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3005 snd_play(&Snds[SND_VASUDAN_BUP]);
3007 // tst x and direction
3011 tst_offset_total = (float)w;
3012 tst_offset = (float)w;
3014 tst_x = (float)gr_screen.max_w;
3015 tst_offset_total = (float)-w;
3016 tst_offset = (float)w;
3024 float diff = (tst_offset_total / 0.5f) * flFrametime;
3030 tst_offset -= fl_abs(diff);
3031 } else if(tst_mode == 2){
3034 tst_offset -= fl_abs(diff);
3038 gr_set_bitmap(tst_bitmap);
3039 gr_bitmap((int)tst_x, (int)tst_y);
3042 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3046 // if we passed the switch point
3047 if(tst_offset <= 0.0f){
3052 tst_stamp = timestamp(1000);
3053 tst_offset = fl_abs(tst_offset_total);
3064 void game_tst_mark(object *objp, ship *shipp)
3073 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3076 sip = &Ship_info[shipp->ship_info_index];
3083 tst_pos = objp->pos;
3084 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3090 extern void render_shields();
3092 void player_repair_frame(float frametime)
3094 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3096 for(idx=0;idx<MAX_PLAYERS;idx++){
3099 np = &Net_players[idx];
3101 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)){
3103 // don't rearm/repair if the player is dead or dying/departing
3104 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3105 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3110 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3111 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3117 #define NUM_FRAMES_TEST 300
3118 #define NUM_MIXED_SOUNDS 16
3119 void do_timing_test(float flFrametime)
3121 static int framecount = 0;
3122 static int test_running = 0;
3123 static float test_time = 0.0f;
3125 static int snds[NUM_MIXED_SOUNDS];
3128 if ( test_running ) {
3130 test_time += flFrametime;
3131 if ( framecount >= NUM_FRAMES_TEST ) {
3133 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3134 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3139 if ( Test_begin == 1 ) {
3145 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3148 // start looping digital sounds
3149 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3150 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3157 DCF(dcf_fov, "Change the field of view")
3160 dc_get_arg(ARG_FLOAT|ARG_NONE);
3161 if ( Dc_arg_type & ARG_NONE ) {
3162 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3163 dc_printf( "Zoom factor reset\n" );
3165 if ( Dc_arg_type & ARG_FLOAT ) {
3166 if (Dc_arg_float < 0.25f) {
3167 Viewer_zoom = 0.25f;
3168 dc_printf("Zoom factor pinned at 0.25.\n");
3169 } else if (Dc_arg_float > 1.25f) {
3170 Viewer_zoom = 1.25f;
3171 dc_printf("Zoom factor pinned at 1.25.\n");
3173 Viewer_zoom = Dc_arg_float;
3179 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3182 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3186 DCF(framerate_cap, "Sets the framerate cap")
3189 dc_get_arg(ARG_INT);
3190 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3191 Framerate_cap = Dc_arg_int;
3193 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3199 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3200 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3201 dc_printf("[n] must be from 1 to 120.\n");
3205 if ( Framerate_cap )
3206 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3208 dc_printf("There is no framerate cap currently active.\n");
3212 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3213 int Show_viewing_from_self = 0;
3215 void say_view_target()
3217 object *view_target;
3219 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3220 view_target = &Objects[Player_ai->target_objnum];
3222 view_target = Player_obj;
3224 if (Game_mode & GM_DEAD) {
3225 if (Player_ai->target_objnum != -1)
3226 view_target = &Objects[Player_ai->target_objnum];
3229 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3230 if (view_target != Player_obj){
3232 char *view_target_name = NULL;
3233 switch(Objects[Player_ai->target_objnum].type) {
3235 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3238 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3239 Viewer_mode &= ~VM_OTHER_SHIP;
3241 case OBJ_JUMP_NODE: {
3242 char jump_node_name[128];
3243 strcpy(jump_node_name, XSTR( "jump node", 184));
3244 view_target_name = jump_node_name;
3245 Viewer_mode &= ~VM_OTHER_SHIP;
3254 if ( view_target_name ) {
3255 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3256 Show_viewing_from_self = 1;
3259 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3260 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3261 Show_viewing_from_self = 1;
3263 if (Show_viewing_from_self)
3264 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3269 Last_view_target = view_target;
3273 float Game_hit_x = 0.0f;
3274 float Game_hit_y = 0.0f;
3276 // Reset at the beginning of each frame
3277 void game_whack_reset()
3283 // Apply a 2d whack to the player
3284 void game_whack_apply( float x, float y )
3286 // Do some force feedback
3287 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3293 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3296 // call to apply a "shudder"
3297 void game_shudder_apply(int time, float intensity)
3299 Game_shudder_time = timestamp(time);
3300 Game_shudder_total = time;
3301 Game_shudder_intensity = intensity;
3304 #define FF_SCALE 10000
3305 void apply_hud_shake(matrix *eye_orient)
3307 if (Viewer_obj == Player_obj) {
3308 physics_info *pi = &Player_obj->phys_info;
3316 // Make eye shake due to afterburner
3317 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3320 dtime = timestamp_until(pi->afterburner_decay);
3324 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3325 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3328 // Make eye shake due to engine wash
3330 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3333 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3334 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3336 // get the intensity
3337 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3341 vm_vec_rand_vec_quick(&rand_vec);
3344 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3348 // make hud shake due to shuddering
3349 if(Game_shudder_time != -1){
3350 // if the timestamp has elapsed
3351 if(timestamp_elapsed(Game_shudder_time)){
3352 Game_shudder_time = -1;
3354 // otherwise apply some shudder
3358 dtime = timestamp_until(Game_shudder_time);
3362 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));
3363 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));
3368 vm_angles_2_matrix(&tm, &tangles);
3369 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3370 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3371 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3372 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3377 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3379 // Player's velocity just before he blew up. Used to keep camera target moving.
3380 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3382 // Set eye_pos and eye_orient based on view mode.
3383 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3387 static int last_Viewer_mode = 0;
3388 static int last_Game_mode = 0;
3389 static int last_Viewer_objnum = -1;
3391 // This code is supposed to detect camera "cuts"... like going between
3394 // determine if we need to regenerate the nebula
3395 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3396 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3397 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3398 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3399 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3400 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3401 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3402 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3403 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3406 // regenerate the nebula
3410 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3411 //mprintf(( "************** Camera cut! ************\n" ));
3412 last_Viewer_mode = Viewer_mode;
3413 last_Game_mode = Game_mode;
3415 // Camera moved. Tell stars & debris to not do blurring.
3421 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3422 player_display_packlock_view();
3425 game_set_view_clip();
3427 if (Game_mode & GM_DEAD) {
3428 vector vec_to_deader, view_pos;
3431 Viewer_mode |= VM_DEAD_VIEW;
3433 if (Player_ai->target_objnum != -1) {
3434 int view_from_player = 1;
3436 if (Viewer_mode & VM_OTHER_SHIP) {
3437 // View from target.
3438 Viewer_obj = &Objects[Player_ai->target_objnum];
3440 last_Viewer_objnum = Player_ai->target_objnum;
3442 if ( Viewer_obj->type == OBJ_SHIP ) {
3443 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3444 view_from_player = 0;
3447 last_Viewer_objnum = -1;
3450 if ( view_from_player ) {
3451 // View target from player ship.
3453 *eye_pos = Player_obj->pos;
3454 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3455 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3458 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3460 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3461 dist += flFrametime * 16.0f;
3463 vm_vec_scale(&vec_to_deader, -dist);
3464 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3466 view_pos = Player_obj->pos;
3468 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3469 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3470 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3471 Dead_player_last_vel = Player_obj->phys_info.vel;
3472 //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));
3473 } else if (Player_ai->target_objnum != -1) {
3474 view_pos = Objects[Player_ai->target_objnum].pos;
3476 // Make camera follow explosion, but gradually slow down.
3477 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3478 view_pos = Player_obj->pos;
3479 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3480 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3483 *eye_pos = Dead_camera_pos;
3485 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3487 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3492 // if supernova shockwave
3493 if(supernova_camera_cut()){
3497 // call it dead view
3498 Viewer_mode |= VM_DEAD_VIEW;
3500 // set eye pos and orient
3501 supernova_set_view(eye_pos, eye_orient);
3503 // If already blown up, these other modes can override.
3504 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3505 Viewer_mode &= ~VM_DEAD_VIEW;
3507 Viewer_obj = Player_obj;
3509 if (Viewer_mode & VM_OTHER_SHIP) {
3510 if (Player_ai->target_objnum != -1){
3511 Viewer_obj = &Objects[Player_ai->target_objnum];
3512 last_Viewer_objnum = Player_ai->target_objnum;
3514 Viewer_mode &= ~VM_OTHER_SHIP;
3515 last_Viewer_objnum = -1;
3518 last_Viewer_objnum = -1;
3521 if (Viewer_mode & VM_EXTERNAL) {
3524 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3525 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3527 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3529 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3530 vm_vec_normalize(&eye_dir);
3531 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3534 // Modify the orientation based on head orientation.
3535 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3537 } else if ( Viewer_mode & VM_CHASE ) {
3540 if ( Viewer_obj->phys_info.speed < 0.1 )
3541 move_dir = Viewer_obj->orient.v.fvec;
3543 move_dir = Viewer_obj->phys_info.vel;
3544 vm_vec_normalize(&move_dir);
3547 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3548 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3549 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3550 vm_vec_normalize(&eye_dir);
3552 // JAS: I added the following code because if you slew up using
3553 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3554 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3555 // call because the up and the forward vector are the same. I fixed
3556 // it by adding in a fraction of the right vector all the time to the
3558 vector tmp_up = Viewer_obj->orient.v.uvec;
3559 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3561 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3564 // Modify the orientation based on head orientation.
3565 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3566 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3567 *eye_pos = Camera_pos;
3569 ship * shipp = &Ships[Player_obj->instance];
3571 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3572 vm_vec_normalize(&eye_dir);
3573 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3576 // get an eye position based upon the correct type of object
3577 switch(Viewer_obj->type){
3579 // make a call to get the eye point for the player object
3580 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3583 // make a call to get the eye point for the player object
3584 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3590 #ifdef JOHNS_DEBUG_CODE
3591 john_debug_stuff(&eye_pos, &eye_orient);
3597 apply_hud_shake(eye_orient);
3599 // setup neb2 rendering
3600 neb2_render_setup(eye_pos, eye_orient);
3604 extern void ai_debug_render_stuff();
3607 int Game_subspace_effect = 0;
3608 DCF_BOOL( subspace, Game_subspace_effect );
3610 // Does everything needed to render a frame
3611 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3615 g3_start_frame(game_zbuffer);
3616 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3618 // maybe offset the HUD (jitter stuff)
3619 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3620 HUD_set_offsets(Viewer_obj, !dont_offset);
3622 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3623 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3624 // must be done before ships are rendered
3625 if ( MULTIPLAYER_CLIENT ) {
3626 shield_point_multi_setup();
3629 if ( Game_subspace_effect ) {
3630 stars_draw(0,0,0,1);
3632 stars_draw(1,1,1,0);
3635 obj_render_all(obj_render);
3636 beam_render_all(); // render all beam weapons
3637 particle_render_all(); // render particles after everything else.
3638 trail_render_all(); // render missilie trails after everything else.
3639 mflash_render_all(); // render all muzzle flashes
3641 // Why do we not show the shield effect in these modes? Seems ok.
3642 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3646 // render nebula lightning
3649 // render local player nebula
3650 neb2_render_player();
3653 ai_debug_render_stuff();
3656 #ifndef RELEASE_REAL
3657 // game_framerate_check();
3661 extern void snd_spew_debug_info();
3662 snd_spew_debug_info();
3665 //================ END OF 3D RENDERING STUFF ====================
3669 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3670 hud_maybe_clear_head_area();
3671 anim_render_all(0, flFrametime);
3674 extern int Multi_display_netinfo;
3675 if(Multi_display_netinfo){
3676 extern void multi_display_netinfo();
3677 multi_display_netinfo();
3680 game_tst_frame_pre();
3683 do_timing_test(flFrametime);
3687 extern int OO_update_index;
3688 multi_rate_display(OO_update_index, 375, 0);
3693 extern void oo_display();
3700 //#define JOHNS_DEBUG_CODE 1
3702 #ifdef JOHNS_DEBUG_CODE
3703 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3705 //if ( keyd_pressed[KEY_LSHIFT] )
3707 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3709 model_subsystem *turret = tsys->system_info;
3711 if (turret->type == SUBSYSTEM_TURRET ) {
3712 vector v.fvec, v.uvec;
3713 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3715 ship_model_start(tobj);
3717 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3718 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3719 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3721 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3723 ship_model_stop(tobj);
3733 // following function for dumping frames for purposes of building trailers.
3736 // function to toggle state of dumping every frame into PCX when playing the game
3737 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3741 if ( Debug_dump_frames == 0 ) {
3743 Debug_dump_frames = 15;
3744 Debug_dump_trigger = 0;
3745 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3746 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3749 Debug_dump_frames = 0;
3750 Debug_dump_trigger = 0;
3751 gr_dump_frame_stop();
3752 dc_printf( "Frame dumping is now OFF\n" );
3758 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3762 if ( Debug_dump_frames == 0 ) {
3764 Debug_dump_frames = 15;
3765 Debug_dump_trigger = 1;
3766 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3767 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3770 Debug_dump_frames = 0;
3771 Debug_dump_trigger = 0;
3772 gr_dump_frame_stop();
3773 dc_printf( "Frame dumping is now OFF\n" );
3779 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3783 if ( Debug_dump_frames == 0 ) {
3785 Debug_dump_frames = 30;
3786 Debug_dump_trigger = 0;
3787 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3788 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3791 Debug_dump_frames = 0;
3792 Debug_dump_trigger = 0;
3793 gr_dump_frame_stop();
3794 dc_printf( "Frame dumping is now OFF\n" );
3800 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3804 if ( Debug_dump_frames == 0 ) {
3806 Debug_dump_frames = 30;
3807 Debug_dump_trigger = 1;
3808 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3809 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3812 Debug_dump_frames = 0;
3813 Debug_dump_trigger = 0;
3814 gr_dump_frame_stop();
3815 dc_printf( "Triggered frame dumping is now OFF\n" );
3821 void game_maybe_dump_frame()
3823 if ( !Debug_dump_frames ){
3827 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3834 Debug_dump_frame_num++;
3840 extern int Player_dead_state;
3842 // Flip the page and time how long it took.
3843 void game_flip_page_and_time_it()
3848 t1 = timer_get_fixed_seconds();
3850 t2 = timer_get_fixed_seconds();
3853 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3854 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3861 void game_simulation_frame()
3863 // blow ships up in multiplayer dogfight
3864 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){
3865 // blow up all non-player ships
3866 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3869 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3871 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)){
3872 moveup = GET_NEXT(moveup);
3875 shipp = &Ships[Objects[moveup->objnum].instance];
3876 sip = &Ship_info[shipp->ship_info_index];
3878 // only blow up small ships
3879 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3880 // function to simply explode a ship where it is currently at
3881 ship_self_destruct( &Objects[moveup->objnum] );
3884 moveup = GET_NEXT(moveup);
3890 // process AWACS stuff - do this first thing
3893 // single player, set Player hits_this_frame to 0
3894 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3895 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3896 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3900 supernova_process();
3901 if(supernova_active() >= 5){
3905 // fire targeting lasers now so that
3906 // 1 - created this frame
3907 // 2 - collide this frame
3908 // 3 - render this frame
3909 // 4 - ignored and deleted next frame
3910 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3912 ship_process_targeting_lasers();
3914 // do this here so that it works for multiplayer
3916 // get viewer direction
3917 int viewer_direction = PHYSICS_VIEWER_REAR;
3919 if(Viewer_mode == 0){
3920 viewer_direction = PHYSICS_VIEWER_FRONT;
3922 if(Viewer_mode & VM_PADLOCK_UP){
3923 viewer_direction = PHYSICS_VIEWER_UP;
3925 else if(Viewer_mode & VM_PADLOCK_REAR){
3926 viewer_direction = PHYSICS_VIEWER_REAR;
3928 else if(Viewer_mode & VM_PADLOCK_LEFT){
3929 viewer_direction = PHYSICS_VIEWER_LEFT;
3931 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3932 viewer_direction = PHYSICS_VIEWER_RIGHT;
3935 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3937 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3940 #define VM_PADLOCK_UP (1 << 7)
3941 #define VM_PADLOCK_REAR (1 << 8)
3942 #define VM_PADLOCK_LEFT (1 << 9)
3943 #define VM_PADLOCK_RIGHT (1 << 10)
3945 // evaluate mission departures and arrivals before we process all objects.
3946 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3948 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3949 // ships/wing packets.
3950 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3951 mission_parse_eval_stuff();
3954 // if we're an observer, move ourselves seperately from the standard physics
3955 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3956 obj_observer_move(flFrametime);
3959 // move all the objects now
3960 obj_move_all(flFrametime);
3962 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3963 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3964 // ship_check_cargo_all();
3965 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3966 mission_eval_goals();
3970 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3971 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3972 training_check_objectives();
3975 // do all interpolation now
3976 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3977 // client side processing of warping in effect stages
3978 multi_do_client_warp(flFrametime);
3980 // client side movement of an observer
3981 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3982 obj_observer_move(flFrametime);
3985 // move all objects - does interpolation now as well
3986 obj_move_all(flFrametime);
3989 // only process the message queue when the player is "in" the game
3990 if ( !Pre_player_entry ){
3991 message_queue_process(); // process any messages send to the player
3994 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3995 message_maybe_distort(); // maybe distort incoming message if comms damaged
3996 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3997 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3998 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
4001 if(!(Game_mode & GM_STANDALONE_SERVER)){
4002 // process some stuff every frame (before frame is rendered)
4003 emp_process_local();
4005 hud_update_frame(); // update hud systems
4007 if (!physics_paused) {
4008 // Move particle system
4009 particle_move_all(flFrametime);
4011 // Move missile trails
4012 trail_move_all(flFrametime);
4014 // process muzzle flashes
4015 mflash_process_all();
4017 // Flash the gun flashes
4018 shipfx_flash_do_frame(flFrametime);
4020 shockwave_move_all(flFrametime); // update all the shockwaves
4023 // subspace missile strikes
4026 obj_snd_do_frame(); // update the object-linked persistant sounds
4027 game_maybe_update_sound_environment();
4028 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4030 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4032 if ( Game_subspace_effect ) {
4033 game_start_subspace_ambient_sound();
4039 // Maybe render and process the dead-popup
4040 void game_maybe_do_dead_popup(float frametime)
4042 if ( popupdead_is_active() ) {
4044 int choice = popupdead_do_frame(frametime);
4046 if ( Game_mode & GM_NORMAL ) {
4050 if(game_do_cd_mission_check(Game_current_mission_filename)){
4051 gameseq_post_event(GS_EVENT_ENTER_GAME);
4053 gameseq_post_event(GS_EVENT_MAIN_MENU);
4058 gameseq_post_event(GS_EVENT_END_GAME);
4063 if(game_do_cd_mission_check(Game_current_mission_filename)){
4064 gameseq_post_event(GS_EVENT_START_GAME);
4066 gameseq_post_event(GS_EVENT_MAIN_MENU);
4070 // this should only happen during a red alert mission
4073 Assert(The_mission.red_alert);
4074 if(!The_mission.red_alert){
4076 if(game_do_cd_mission_check(Game_current_mission_filename)){
4077 gameseq_post_event(GS_EVENT_START_GAME);
4079 gameseq_post_event(GS_EVENT_MAIN_MENU);
4084 // choose the previous mission
4085 mission_campaign_previous_mission();
4087 if(game_do_cd_mission_check(Game_current_mission_filename)){
4088 gameseq_post_event(GS_EVENT_START_GAME);
4090 gameseq_post_event(GS_EVENT_MAIN_MENU);
4101 case POPUPDEAD_DO_MAIN_HALL:
4102 multi_quit_game(PROMPT_NONE,-1);
4105 case POPUPDEAD_DO_RESPAWN:
4106 multi_respawn_normal();
4107 event_music_player_respawn();
4110 case POPUPDEAD_DO_OBSERVER:
4111 multi_respawn_observer();
4112 event_music_player_respawn_as_observer();
4121 if ( leave_popup ) {
4127 // returns true if player is actually in a game_play stats
4128 int game_actually_playing()
4132 state = gameseq_get_state();
4133 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4139 // Draw the 2D HUD gauges
4140 void game_render_hud_2d()
4142 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4146 HUD_render_2d(flFrametime);
4150 // Draw the 3D-dependant HUD gauges
4151 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4153 g3_start_frame(0); // 0 = turn zbuffering off
4154 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4156 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4157 HUD_render_3d(flFrametime);
4161 game_sunspot_process(flFrametime);
4163 // Diminish the palette effect
4164 game_flash_diminish(flFrametime);
4172 int actually_playing;
4173 fix total_time1, total_time2;
4174 fix render2_time1=0, render2_time2=0;
4175 fix render3_time1=0, render3_time2=0;
4176 fix flip_time1=0, flip_time2=0;
4177 fix clear_time1=0, clear_time2=0;
4183 if (Framerate_delay) {
4184 int start_time = timer_get_milliseconds();
4185 while (timer_get_milliseconds() < start_time + Framerate_delay)
4191 demo_do_frame_start();
4193 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4198 // start timing frame
4199 timing_frame_start();
4201 total_time1 = timer_get_fixed_seconds();
4203 // var to hold which state we are in
4204 actually_playing = game_actually_playing();
4206 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4207 if (!(Game_mode & GM_STANDALONE_SERVER)){
4208 Assert( OBJ_INDEX(Player_obj) >= 0 );
4212 if (Missiontime > Entry_delay_time){
4213 Pre_player_entry = 0;
4215 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4218 // Note: These are done even before the player enters, else buffers can overflow.
4219 if (! (Game_mode & GM_STANDALONE_SERVER)){
4223 shield_frame_init();
4225 if ( Player->control_mode != PCM_NORMAL )
4228 if ( !Pre_player_entry && actually_playing ) {
4229 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4231 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4232 game_process_keys();
4234 // don't read flying controls if we're playing a demo back
4235 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4236 read_player_controls( Player_obj, flFrametime);
4240 // if we're not the master, we may have to send the server-critical ship status button_info bits
4241 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4242 multi_maybe_send_ship_status();
4247 // Reset the whack stuff
4250 // These two lines must be outside of Pre_player_entry code,
4251 // otherwise too many lights are added.
4254 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4258 game_simulation_frame();
4260 // if not actually in a game play state, then return. This condition could only be true in
4261 // a multiplayer game.
4262 if ( !actually_playing ) {
4263 Assert( Game_mode & GM_MULTIPLAYER );
4267 if (!Pre_player_entry) {
4268 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4269 clear_time1 = timer_get_fixed_seconds();
4270 // clear the screen to black
4272 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4276 clear_time2 = timer_get_fixed_seconds();
4277 render3_time1 = timer_get_fixed_seconds();
4278 game_render_frame_setup(&eye_pos, &eye_orient);
4279 game_render_frame( &eye_pos, &eye_orient );
4281 // save the eye position and orientation
4282 if ( Game_mode & GM_MULTIPLAYER ) {
4283 Net_player->s_info.eye_pos = eye_pos;
4284 Net_player->s_info.eye_orient = eye_orient;
4287 hud_show_target_model();
4289 // check to see if we should display the death died popup
4290 if(Game_mode & GM_DEAD_BLEW_UP){
4291 if(Game_mode & GM_MULTIPLAYER){
4292 // catch the situation where we're supposed to be warping out on this transition
4293 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4294 gameseq_post_event(GS_EVENT_DEBRIEF);
4295 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4296 Player_died_popup_wait = -1;
4300 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4301 Player_died_popup_wait = -1;
4307 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4308 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4309 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4310 if(!popupdead_is_active()){
4314 Player_multi_died_check = -1;
4318 render3_time2 = timer_get_fixed_seconds();
4319 render2_time1 = timer_get_fixed_seconds();
4322 game_get_framerate();
4323 game_show_framerate();
4325 game_show_time_left();
4327 // Draw the 2D HUD gauges
4328 if(supernova_active() < 3){
4329 game_render_hud_2d();
4332 game_set_view_clip();
4334 // Draw 3D HUD gauges
4335 game_render_hud_3d(&eye_pos, &eye_orient);
4339 render2_time2 = timer_get_fixed_seconds();
4341 // maybe render and process the dead popup
4342 game_maybe_do_dead_popup(flFrametime);
4344 // start timing frame
4345 timing_frame_stop();
4346 // timing_display(30, 10);
4348 // If a regular popup is active, don't flip (popup code flips)
4349 if( !popup_running_state() ){
4350 flip_time1 = timer_get_fixed_seconds();
4351 game_flip_page_and_time_it();
4352 flip_time2 = timer_get_fixed_seconds();
4356 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4359 game_show_standalone_framerate();
4363 game_do_training_checks();
4366 // process lightning (nebula only)
4369 total_time2 = timer_get_fixed_seconds();
4371 // Got some timing numbers
4372 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4373 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4374 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4375 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4376 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4379 demo_do_frame_end();
4381 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4387 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4388 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4389 // died. This resulted in screwed up death sequences.
4391 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4392 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4393 static int timer_paused=0;
4394 #if defined(TIMER_TEST) && !defined(NDEBUG)
4395 static int stop_count,start_count;
4396 static int time_stopped,time_started;
4398 int saved_timestamp_ticker = -1;
4400 void game_reset_time()
4402 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4406 // Last_time = timer_get_fixed_seconds();
4412 void game_stop_time()
4414 if (timer_paused==0) {
4416 time = timer_get_fixed_seconds();
4417 // Save how much time progressed so far in the frame so we can
4418 // use it when we unpause.
4419 Last_delta_time = time - Last_time;
4421 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4422 if (Last_delta_time < 0) {
4423 #if defined(TIMER_TEST) && !defined(NDEBUG)
4424 Int3(); //get Matt!!!!
4426 Last_delta_time = 0;
4428 #if defined(TIMER_TEST) && !defined(NDEBUG)
4429 time_stopped = time;
4432 // Stop the timer_tick stuff...
4433 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4434 saved_timestamp_ticker = timestamp_ticker;
4438 #if defined(TIMER_TEST) && !defined(NDEBUG)
4443 void game_start_time()
4446 Assert(timer_paused >= 0);
4447 if (timer_paused==0) {
4449 time = timer_get_fixed_seconds();
4450 #if defined(TIMER_TEST) && !defined(NDEBUG)
4452 Int3(); //get Matt!!!!
4455 // Take current time, and set it backwards to account for time
4456 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4457 // will be correct when it goes to calculate the frametime next
4459 Last_time = time - Last_delta_time;
4460 #if defined(TIMER_TEST) && !defined(NDEBUG)
4461 time_started = time;
4464 // Restore the timer_tick stuff...
4465 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4466 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4467 timestamp_ticker = saved_timestamp_ticker;
4468 saved_timestamp_ticker = -1;
4471 #if defined(TIMER_TEST) && !defined(NDEBUG)
4477 void game_set_frametime(int state)
4480 float frame_cap_diff;
4482 thistime = timer_get_fixed_seconds();
4484 if ( Last_time == 0 )
4485 Frametime = F1_0 / 30;
4487 Frametime = thistime - Last_time;
4489 // Frametime = F1_0 / 30;
4491 fix debug_frametime = Frametime; // Just used to display frametime.
4493 // If player hasn't entered mission yet, make frame take 1/4 second.
4494 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4497 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4499 fix frame_speed = F1_0 / Debug_dump_frames;
4501 if (Frametime > frame_speed ){
4502 nprintf(("warning","slow frame: %x\n",Frametime));
4505 thistime = timer_get_fixed_seconds();
4506 Frametime = thistime - Last_time;
4507 } while (Frametime < frame_speed );
4509 Frametime = frame_speed;
4513 Assert( Framerate_cap > 0 );
4515 // Cap the framerate so it doesn't get too high.
4519 cap = F1_0/Framerate_cap;
4520 if (Frametime < cap) {
4521 thistime = cap - Frametime;
4522 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4523 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4525 thistime = timer_get_fixed_seconds();
4529 if((Game_mode & GM_STANDALONE_SERVER) &&
4530 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4532 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4533 Sleep((DWORD)(frame_cap_diff*1000));
4535 thistime += fl2f((frame_cap_diff));
4537 Frametime = thistime - Last_time;
4540 // If framerate is too low, cap it.
4541 if (Frametime > MAX_FRAMETIME) {
4543 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4545 // to remove warnings in release build
4546 debug_frametime = fl2f(flFrametime);
4548 Frametime = MAX_FRAMETIME;
4551 Frametime = fixmul(Frametime, Game_time_compression);
4553 Last_time = thistime;
4554 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4556 flFrametime = f2fl(Frametime);
4557 //if(!(Game_mode & GM_PLAYING_DEMO)){
4558 timestamp_inc(flFrametime);
4560 /* if ((Framecount > 0) && (Framecount < 10)) {
4561 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4566 // This is called from game_do_frame(), and from navmap_do_frame()
4567 void game_update_missiontime()
4569 // TODO JAS: Put in if and move this into game_set_frametime,
4570 // fix navmap to call game_stop/start_time
4571 //if ( !timer_paused )
4572 Missiontime += Frametime;
4575 void game_do_frame()
4577 game_set_frametime(GS_STATE_GAME_PLAY);
4578 game_update_missiontime();
4580 if (Game_mode & GM_STANDALONE_SERVER) {
4581 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4584 if ( game_single_step && (last_single_step == game_single_step) ) {
4585 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4586 while( key_checkch() == 0 )
4588 os_set_title( XSTR( "FreeSpace", 171) );
4589 Last_time = timer_get_fixed_seconds();
4592 last_single_step = game_single_step;
4594 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4595 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4599 Keep_mouse_centered = 0;
4600 monitor_update(); // Update monitor variables
4603 void multi_maybe_do_frame()
4605 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4610 int Joymouse_button_status = 0;
4612 // Flush all input devices
4620 Joymouse_button_status = 0;
4622 //mprintf(("Game flush!\n" ));
4625 // function for multiplayer only which calls game_do_state_common() when running the
4627 void game_do_dc_networking()
4629 Assert( Game_mode & GM_MULTIPLAYER );
4631 game_do_state_common( gameseq_get_state() );
4634 // Call this whenever in a loop, or when you need to check for a keystroke.
4635 int game_check_key()
4641 // convert keypad enter to normal enter
4642 if ((k & KEY_MASK) == KEY_PADENTER)
4643 k = (k & ~KEY_MASK) | KEY_ENTER;
4650 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4651 static int Demo_show_trailer_timestamp = 0;
4653 void demo_reset_trailer_timer()
4655 Demo_show_trailer_timestamp = timer_get_milliseconds();
4658 void demo_maybe_show_trailer(int k)
4661 // if key pressed, reset demo trailer timer
4663 demo_reset_trailer_timer();
4667 // if mouse moved, reset demo trailer timer
4670 mouse_get_delta(&dx, &dy);
4671 if ( (dx > 0) || (dy > 0) ) {
4672 demo_reset_trailer_timer();
4676 // if joystick has moved, reset demo trailer timer
4679 joy_get_delta(&dx, &dy);
4680 if ( (dx > 0) || (dy > 0) ) {
4681 demo_reset_trailer_timer();
4685 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4686 // the low-level code. Ugly, I know... but was the simplest and most
4689 // if 30 seconds since last demo trailer time reset, launch movie
4690 if ( os_foreground() ) {
4691 int now = timer_get_milliseconds();
4692 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4693 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4695 movie_play( NOX("fstrailer2.mve") );
4696 demo_reset_trailer_timer();
4704 // same as game_check_key(), except this is used while actually in the game. Since there
4705 // generally are differences between game control keys and general UI keys, makes sense to
4706 // have seperate functions for each case. If you are not checking a game control while in a
4707 // mission, you should probably be using game_check_key() instead.
4712 if (!os_foreground()) {
4717 // If we're in a single player game, pause it.
4718 if (!(Game_mode & GM_MULTIPLAYER)){
4719 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4720 game_process_pause_key();
4728 demo_maybe_show_trailer(k);
4731 // Move the mouse cursor with the joystick.
4732 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4733 // Move the mouse cursor with the joystick
4737 joy_get_pos( &jx, &jy, &jz, &jr );
4739 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4740 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4743 mouse_get_real_pos( &mx, &my );
4744 mouse_set_pos( mx+dx, my+dy );
4749 m = mouse_down(MOUSE_LEFT_BUTTON);
4751 if ( j != Joymouse_button_status ) {
4752 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4753 Joymouse_button_status = j;
4755 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4756 } else if ( (!j) && (m) ) {
4757 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4762 // if we should be ignoring keys because of some multiplayer situations
4763 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4767 // If a popup is running, don't process all the Fn keys
4768 if( popup_active() ) {
4772 state = gameseq_get_state();
4774 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4777 case KEY_DEBUGGED + KEY_BACKSP:
4782 launch_context_help();
4787 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4789 // don't allow f2 while warping out in multiplayer
4790 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4795 case GS_STATE_INITIAL_PLAYER_SELECT:
4796 case GS_STATE_OPTIONS_MENU:
4797 case GS_STATE_HUD_CONFIG:
4798 case GS_STATE_CONTROL_CONFIG:
4799 case GS_STATE_DEATH_DIED:
4800 case GS_STATE_DEATH_BLEW_UP:
4801 case GS_STATE_VIEW_MEDALS:
4805 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4812 // hotkey selection screen -- only valid from briefing and beyond.
4815 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) ) {
4816 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4822 case KEY_DEBUGGED + KEY_F3:
4823 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4826 case KEY_DEBUGGED + KEY_F4:
4827 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4831 if(Game_mode & GM_MULTIPLAYER){
4832 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4833 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4837 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4838 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4844 case KEY_ESC | KEY_SHIFTED:
4845 // make sure to quit properly out of multiplayer
4846 if(Game_mode & GM_MULTIPLAYER){
4847 multi_quit_game(PROMPT_NONE);
4850 gameseq_post_event( GS_EVENT_QUIT_GAME );
4855 case KEY_DEBUGGED + KEY_P:
4858 case KEY_PRINT_SCRN:
4860 static int counter = 0;
4865 sprintf( tmp_name, NOX("screen%02d"), counter );
4867 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4868 gr_print_screen(tmp_name);
4876 case KEY_SHIFTED | KEY_ENTER: {
4878 #if !defined(NDEBUG)
4880 if ( Game_mode & GM_NORMAL ){
4884 // if we're in multiplayer mode, do some special networking
4885 if(Game_mode & GM_MULTIPLAYER){
4886 debug_console(game_do_dc_networking);
4893 if ( Game_mode & GM_NORMAL )
4907 gameseq_post_event(GS_EVENT_QUIT_GAME);
4910 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4913 void camera_set_position( vector *pos )
4918 void camera_set_orient( matrix *orient )
4920 Camera_orient = *orient;
4923 void camera_set_velocity( vector *vel, int instantaneous )
4925 Camera_desired_velocity.xyz.x = 0.0f;
4926 Camera_desired_velocity.xyz.y = 0.0f;
4927 Camera_desired_velocity.xyz.z = 0.0f;
4929 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4930 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4931 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4933 if ( instantaneous ) {
4934 Camera_velocity = Camera_desired_velocity;
4942 vector new_vel, delta_pos;
4944 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4945 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4946 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4948 Camera_velocity = new_vel;
4950 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4952 vm_vec_add2( &Camera_pos, &delta_pos );
4954 float ot = Camera_time+0.0f;
4956 Camera_time += flFrametime;
4958 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4961 tmp.xyz.z = 4.739f; // always go this fast forward.
4963 // pick x and y velocities so they are always on a
4964 // circle with a 25 m radius.
4966 float tmp_angle = frand()*PI2;
4968 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4969 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4971 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4973 //mprintf(( "Changing velocity!\n" ));
4974 camera_set_velocity( &tmp, 0 );
4977 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4978 vector tmp = { 0.0f, 0.0f, 0.0f };
4979 camera_set_velocity( &tmp, 0 );
4984 void end_demo_campaign_do()
4986 #if defined(FS2_DEMO)
4987 // show upsell screens
4988 demo_upsell_show_screens();
4989 #elif defined(OEM_BUILD)
4990 // show oem upsell screens
4991 oem_upsell_show_screens();
4994 // drop into main hall
4995 gameseq_post_event( GS_EVENT_MAIN_MENU );
4998 // All code to process events. This is the only place
4999 // that you should change the state of the game.
5000 void game_process_event( int current_state, int event )
5002 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
5005 case GS_EVENT_SIMULATOR_ROOM:
5006 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5009 case GS_EVENT_MAIN_MENU:
5010 gameseq_set_state(GS_STATE_MAIN_MENU);
5013 case GS_EVENT_OPTIONS_MENU:
5014 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5017 case GS_EVENT_BARRACKS_MENU:
5018 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5021 case GS_EVENT_TECH_MENU:
5022 gameseq_set_state(GS_STATE_TECH_MENU);
5025 case GS_EVENT_TRAINING_MENU:
5026 gameseq_set_state(GS_STATE_TRAINING_MENU);
5029 case GS_EVENT_START_GAME:
5030 Select_default_ship = 0;
5031 Player_multi_died_check = -1;
5032 gameseq_set_state(GS_STATE_CMD_BRIEF);
5035 case GS_EVENT_START_BRIEFING:
5036 gameseq_set_state(GS_STATE_BRIEFING);
5039 case GS_EVENT_DEBRIEF:
5040 // did we end the campaign in the main freespace 2 single player campaign?
5041 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5042 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5044 gameseq_set_state(GS_STATE_DEBRIEF);
5047 Player_multi_died_check = -1;
5050 case GS_EVENT_SHIP_SELECTION:
5051 gameseq_set_state( GS_STATE_SHIP_SELECT );
5054 case GS_EVENT_WEAPON_SELECTION:
5055 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5058 case GS_EVENT_ENTER_GAME:
5060 // maybe start recording a demo
5062 demo_start_record("test.fsd");
5066 if (Game_mode & GM_MULTIPLAYER) {
5067 // if we're respawning, make sure we change the view mode so that the hud shows up
5068 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5072 gameseq_set_state(GS_STATE_GAME_PLAY);
5074 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5077 Player_multi_died_check = -1;
5079 // clear multiplayer button info
5080 extern button_info Multi_ship_status_bi;
5081 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5083 Start_time = f2fl(timer_get_approx_seconds());
5085 mprintf(("Entering game at time = %7.3f\n", Start_time));
5089 case GS_EVENT_START_GAME_QUICK:
5090 Select_default_ship = 1;
5091 gameseq_post_event(GS_EVENT_ENTER_GAME);
5095 case GS_EVENT_END_GAME:
5096 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5097 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5098 gameseq_set_state(GS_STATE_MAIN_MENU);
5103 Player_multi_died_check = -1;
5106 case GS_EVENT_QUIT_GAME:
5107 main_hall_stop_music();
5108 main_hall_stop_ambient();
5109 gameseq_set_state(GS_STATE_QUIT_GAME);
5111 Player_multi_died_check = -1;
5114 case GS_EVENT_GAMEPLAY_HELP:
5115 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5118 case GS_EVENT_PAUSE_GAME:
5119 gameseq_push_state(GS_STATE_GAME_PAUSED);
5122 case GS_EVENT_DEBUG_PAUSE_GAME:
5123 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5126 case GS_EVENT_TRAINING_PAUSE:
5127 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5130 case GS_EVENT_PREVIOUS_STATE:
5131 gameseq_pop_state();
5134 case GS_EVENT_TOGGLE_FULLSCREEN:
5135 #ifndef HARDWARE_ONLY
5137 if ( gr_screen.mode == GR_SOFTWARE ) {
5138 gr_init( GR_640, GR_DIRECTDRAW );
5139 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5140 gr_init( GR_640, GR_SOFTWARE );
5146 case GS_EVENT_TOGGLE_GLIDE:
5148 if ( gr_screen.mode != GR_GLIDE ) {
5149 gr_init( GR_640, GR_GLIDE );
5151 gr_init( GR_640, GR_SOFTWARE );
5156 case GS_EVENT_LOAD_MISSION_MENU:
5157 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5160 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5161 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5164 case GS_EVENT_HUD_CONFIG:
5165 gameseq_push_state( GS_STATE_HUD_CONFIG );
5168 case GS_EVENT_CONTROL_CONFIG:
5169 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5172 case GS_EVENT_DEATH_DIED:
5173 gameseq_set_state( GS_STATE_DEATH_DIED );
5176 case GS_EVENT_DEATH_BLEW_UP:
5177 if ( current_state == GS_STATE_DEATH_DIED ) {
5178 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5179 event_music_player_death();
5181 // multiplayer clients set their extra check here
5182 if(Game_mode & GM_MULTIPLAYER){
5183 // set the multi died absolute last chance check
5184 Player_multi_died_check = time(NULL);
5187 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5191 case GS_EVENT_NEW_CAMPAIGN:
5192 if (!mission_load_up_campaign()){
5193 readyroom_continue_campaign();
5196 Player_multi_died_check = -1;
5199 case GS_EVENT_CAMPAIGN_CHEAT:
5200 if (!mission_load_up_campaign()){
5202 // bash campaign value
5203 extern char Main_hall_campaign_cheat[512];
5206 // look for the mission
5207 for(idx=0; idx<Campaign.num_missions; idx++){
5208 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5209 Campaign.next_mission = idx;
5210 Campaign.prev_mission = idx - 1;
5217 readyroom_continue_campaign();
5220 Player_multi_died_check = -1;
5223 case GS_EVENT_CAMPAIGN_ROOM:
5224 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5227 case GS_EVENT_CMD_BRIEF:
5228 gameseq_set_state(GS_STATE_CMD_BRIEF);
5231 case GS_EVENT_RED_ALERT:
5232 gameseq_set_state(GS_STATE_RED_ALERT);
5235 case GS_EVENT_CREDITS:
5236 gameseq_set_state( GS_STATE_CREDITS );
5239 case GS_EVENT_VIEW_MEDALS:
5240 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5243 case GS_EVENT_SHOW_GOALS:
5244 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5247 case GS_EVENT_HOTKEY_SCREEN:
5248 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5251 // multiplayer stuff follow these comments
5253 case GS_EVENT_MULTI_JOIN_GAME:
5254 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5257 case GS_EVENT_MULTI_HOST_SETUP:
5258 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5261 case GS_EVENT_MULTI_CLIENT_SETUP:
5262 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5265 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5266 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5269 case GS_EVENT_MULTI_STD_WAIT:
5270 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5273 case GS_EVENT_STANDALONE_MAIN:
5274 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5277 case GS_EVENT_MULTI_PAUSE:
5278 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5281 case GS_EVENT_INGAME_PRE_JOIN:
5282 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5285 case GS_EVENT_EVENT_DEBUG:
5286 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5289 // Start a warpout where player automatically goes 70 no matter what
5290 // and can't cancel out of it.
5291 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5292 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5294 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5295 Player->saved_viewer_mode = Viewer_mode;
5296 Player->control_mode = PCM_WARPOUT_STAGE1;
5297 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5298 Warpout_time = 0.0f; // Start timer!
5301 case GS_EVENT_PLAYER_WARPOUT_START:
5302 if ( Player->control_mode != PCM_NORMAL ) {
5303 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5305 Player->saved_viewer_mode = Viewer_mode;
5306 Player->control_mode = PCM_WARPOUT_STAGE1;
5307 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5308 Warpout_time = 0.0f; // Start timer!
5309 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5313 case GS_EVENT_PLAYER_WARPOUT_STOP:
5314 if ( Player->control_mode != PCM_NORMAL ) {
5315 if ( !Warpout_forced ) { // cannot cancel forced warpout
5316 Player->control_mode = PCM_NORMAL;
5317 Viewer_mode = Player->saved_viewer_mode;
5318 hud_subspace_notify_abort();
5319 mprintf(( "Player put back to normal mode.\n" ));
5320 if ( Warpout_sound > -1 ) {
5321 snd_stop( Warpout_sound );
5328 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5329 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5330 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5331 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5333 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5334 shipfx_warpout_start( Player_obj );
5335 Player->control_mode = PCM_WARPOUT_STAGE2;
5336 Player->saved_viewer_mode = Viewer_mode;
5337 Viewer_mode |= VM_WARP_CHASE;
5339 vector tmp = Player_obj->pos;
5341 ship_get_eye( &tmp, &tmp_m, Player_obj );
5342 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5343 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5344 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5346 camera_set_position( &tmp );
5347 camera_set_orient( &Player_obj->orient );
5348 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5350 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5351 camera_set_velocity( &tmp_vel, 1);
5355 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5356 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5357 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5358 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5360 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5361 Player->control_mode = PCM_WARPOUT_STAGE3;
5365 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5366 mprintf(( "Player warped out. Going to debriefing!\n" ));
5367 Player->control_mode = PCM_NORMAL;
5368 Viewer_mode = Player->saved_viewer_mode;
5371 // we have a special debriefing screen for multiplayer furballs
5372 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5373 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5375 // do the normal debriefing for all other situations
5377 gameseq_post_event(GS_EVENT_DEBRIEF);
5381 case GS_EVENT_STANDALONE_POSTGAME:
5382 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5385 case GS_EVENT_INITIAL_PLAYER_SELECT:
5386 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5389 case GS_EVENT_GAME_INIT:
5390 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5391 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5393 // see if the command line option has been set to use the last pilot, and act acoordingly
5394 if( player_select_get_last_pilot() ) {
5395 // always enter the main menu -- do the automatic network startup stuff elsewhere
5396 // so that we still have valid checks for networking modes, etc.
5397 gameseq_set_state(GS_STATE_MAIN_MENU);
5399 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5404 case GS_EVENT_MULTI_MISSION_SYNC:
5405 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5408 case GS_EVENT_MULTI_START_GAME:
5409 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5412 case GS_EVENT_MULTI_HOST_OPTIONS:
5413 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5416 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5417 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5420 case GS_EVENT_TEAM_SELECT:
5421 gameseq_set_state(GS_STATE_TEAM_SELECT);
5424 case GS_EVENT_END_CAMPAIGN:
5425 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5428 case GS_EVENT_END_DEMO:
5429 gameseq_set_state(GS_STATE_END_DEMO);
5432 case GS_EVENT_LOOP_BRIEF:
5433 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5442 // Called when a state is being left.
5443 // The current state is still at old_state, but as soon as
5444 // this function leaves, then the current state will become
5445 // new state. You should never try to change the state
5446 // in here... if you think you need to, you probably really
5447 // need to post an event, not change the state.
5448 void game_leave_state( int old_state, int new_state )
5450 int end_mission = 1;
5452 switch (new_state) {
5453 case GS_STATE_GAME_PAUSED:
5454 case GS_STATE_DEBUG_PAUSED:
5455 case GS_STATE_OPTIONS_MENU:
5456 case GS_STATE_CONTROL_CONFIG:
5457 case GS_STATE_MISSION_LOG_SCROLLBACK:
5458 case GS_STATE_DEATH_DIED:
5459 case GS_STATE_SHOW_GOALS:
5460 case GS_STATE_HOTKEY_SCREEN:
5461 case GS_STATE_MULTI_PAUSED:
5462 case GS_STATE_TRAINING_PAUSED:
5463 case GS_STATE_EVENT_DEBUG:
5464 case GS_STATE_GAMEPLAY_HELP:
5465 end_mission = 0; // these events shouldn't end a mission
5469 switch (old_state) {
5470 case GS_STATE_BRIEFING:
5471 brief_stop_voices();
5472 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5473 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5474 && (new_state != GS_STATE_TEAM_SELECT) ){
5475 common_select_close();
5476 if ( new_state == GS_STATE_MAIN_MENU ) {
5477 freespace_stop_mission();
5481 // COMMAND LINE OPTION
5482 if (Cmdline_multi_stream_chat_to_file){
5483 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5484 cfclose(Multi_chat_stream);
5488 case GS_STATE_DEBRIEF:
5489 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5494 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5495 multi_df_debrief_close();
5498 case GS_STATE_LOAD_MISSION_MENU:
5499 mission_load_menu_close();
5502 case GS_STATE_SIMULATOR_ROOM:
5506 case GS_STATE_CAMPAIGN_ROOM:
5507 campaign_room_close();
5510 case GS_STATE_CMD_BRIEF:
5511 if (new_state == GS_STATE_OPTIONS_MENU) {
5516 if (new_state == GS_STATE_MAIN_MENU)
5517 freespace_stop_mission();
5522 case GS_STATE_RED_ALERT:
5526 case GS_STATE_SHIP_SELECT:
5527 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5528 new_state != GS_STATE_HOTKEY_SCREEN &&
5529 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5530 common_select_close();
5531 if ( new_state == GS_STATE_MAIN_MENU ) {
5532 freespace_stop_mission();
5537 case GS_STATE_WEAPON_SELECT:
5538 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5539 new_state != GS_STATE_HOTKEY_SCREEN &&
5540 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5541 common_select_close();
5542 if ( new_state == GS_STATE_MAIN_MENU ) {
5543 freespace_stop_mission();
5548 case GS_STATE_TEAM_SELECT:
5549 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5550 new_state != GS_STATE_HOTKEY_SCREEN &&
5551 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5552 common_select_close();
5553 if ( new_state == GS_STATE_MAIN_MENU ) {
5554 freespace_stop_mission();
5559 case GS_STATE_MAIN_MENU:
5560 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5567 case GS_STATE_OPTIONS_MENU:
5568 //game_start_time();
5569 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5570 multi_join_clear_game_list();
5572 options_menu_close();
5575 case GS_STATE_BARRACKS_MENU:
5576 if(new_state != GS_STATE_VIEW_MEDALS){
5581 case GS_STATE_MISSION_LOG_SCROLLBACK:
5582 hud_scrollback_close();
5585 case GS_STATE_TRAINING_MENU:
5586 training_menu_close();
5589 case GS_STATE_GAME_PLAY:
5590 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5591 player_save_target_and_weapon_link_prefs();
5592 game_stop_looped_sounds();
5595 sound_env_disable();
5596 joy_ff_stop_effects();
5598 // stop game time under certain conditions
5599 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5604 // shut down any recording or playing demos
5609 // when in multiplayer and going back to the main menu, send a leave game packet
5610 // right away (before calling stop mission). stop_mission was taking to long to
5611 // close mission down and I want people to get notified ASAP.
5612 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5613 multi_quit_game(PROMPT_NONE);
5616 freespace_stop_mission();
5617 Game_time_compression = F1_0;
5621 case GS_STATE_TECH_MENU:
5625 case GS_STATE_TRAINING_PAUSED:
5626 Training_num_lines = 0;
5627 // fall through to GS_STATE_GAME_PAUSED
5629 case GS_STATE_GAME_PAUSED:
5631 if ( end_mission ) {
5636 case GS_STATE_DEBUG_PAUSED:
5639 pause_debug_close();
5643 case GS_STATE_HUD_CONFIG:
5647 // join/start a game
5648 case GS_STATE_MULTI_JOIN_GAME:
5649 if(new_state != GS_STATE_OPTIONS_MENU){
5650 multi_join_game_close();
5654 case GS_STATE_MULTI_HOST_SETUP:
5655 case GS_STATE_MULTI_CLIENT_SETUP:
5656 // if this is just the host going into the options screen, don't do anything
5657 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5661 // close down the proper state
5662 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5663 multi_create_game_close();
5665 multi_game_client_setup_close();
5668 // COMMAND LINE OPTION
5669 if (Cmdline_multi_stream_chat_to_file){
5670 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5671 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5672 cfclose(Multi_chat_stream);
5677 case GS_STATE_CONTROL_CONFIG:
5678 control_config_close();
5681 case GS_STATE_DEATH_DIED:
5682 Game_mode &= ~GM_DEAD_DIED;
5684 // early end while respawning or blowing up in a multiplayer game
5685 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5687 freespace_stop_mission();
5691 case GS_STATE_DEATH_BLEW_UP:
5692 Game_mode &= ~GM_DEAD_BLEW_UP;
5694 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5695 // to determine if I should do anything.
5696 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5698 freespace_stop_mission();
5701 // if we are not respawing as an observer or as a player, our new state will not
5702 // be gameplay state.
5703 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5704 game_stop_time(); // hasn't been called yet!!
5705 freespace_stop_mission();
5711 case GS_STATE_CREDITS:
5715 case GS_STATE_VIEW_MEDALS:
5719 case GS_STATE_SHOW_GOALS:
5720 mission_show_goals_close();
5723 case GS_STATE_HOTKEY_SCREEN:
5724 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5725 mission_hotkey_close();
5729 case GS_STATE_MULTI_MISSION_SYNC:
5730 // if we're moving into the options menu, don't do anything
5731 if(new_state == GS_STATE_OPTIONS_MENU){
5735 Assert( Game_mode & GM_MULTIPLAYER );
5737 if ( new_state == GS_STATE_GAME_PLAY ){
5738 // palette_restore_palette();
5740 // change a couple of flags to indicate our state!!!
5741 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5742 send_netplayer_update_packet();
5744 // set the game mode
5745 Game_mode |= GM_IN_MISSION;
5749 case GS_STATE_VIEW_CUTSCENES:
5750 cutscenes_screen_close();
5753 case GS_STATE_MULTI_STD_WAIT:
5754 multi_standalone_wait_close();
5757 case GS_STATE_STANDALONE_MAIN:
5758 standalone_main_close();
5759 if(new_state == GS_STATE_MULTI_STD_WAIT){
5760 init_multiplayer_stats();
5764 case GS_STATE_MULTI_PAUSED:
5765 // if ( end_mission ){
5770 case GS_STATE_INGAME_PRE_JOIN:
5771 multi_ingame_select_close();
5774 case GS_STATE_STANDALONE_POSTGAME:
5775 multi_standalone_postgame_close();
5778 case GS_STATE_INITIAL_PLAYER_SELECT:
5779 player_select_close();
5782 case GS_STATE_MULTI_START_GAME:
5783 multi_start_game_close();
5786 case GS_STATE_MULTI_HOST_OPTIONS:
5787 multi_host_options_close();
5790 case GS_STATE_END_OF_CAMPAIGN:
5791 mission_campaign_end_close();
5794 case GS_STATE_LOOP_BRIEF:
5800 // Called when a state is being entered.
5801 // The current state is set to the state we're entering at
5802 // this point, and old_state is set to the state we're coming
5803 // from. You should never try to change the state
5804 // in here... if you think you need to, you probably really
5805 // need to post an event, not change the state.
5807 void game_enter_state( int old_state, int new_state )
5809 switch (new_state) {
5810 case GS_STATE_MAIN_MENU:
5811 // in multiplayer mode, be sure that we are not doing networking anymore.
5812 if ( Game_mode & GM_MULTIPLAYER ) {
5813 Assert( Net_player != NULL );
5814 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5817 Game_time_compression = F1_0;
5819 // determine which ship this guy is currently based on
5820 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5823 if (Player->on_bastion) {
5831 case GS_STATE_BRIEFING:
5832 main_hall_stop_music();
5833 main_hall_stop_ambient();
5835 if (Game_mode & GM_NORMAL) {
5836 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5837 // MWA: or from options or hotkey screens
5838 // JH: or if the command brief state already did this
5839 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5840 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5841 && (old_state != GS_STATE_CMD_BRIEF) ) {
5842 if ( !game_start_mission() ) // this should put us into a new state on failure!
5846 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5847 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5848 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5850 Game_time_compression = F1_0;
5852 if ( red_alert_mission() ) {
5853 gameseq_post_event(GS_EVENT_RED_ALERT);
5860 case GS_STATE_DEBRIEF:
5861 game_stop_looped_sounds();
5862 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5863 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5868 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5869 multi_df_debrief_init();
5872 case GS_STATE_LOAD_MISSION_MENU:
5873 mission_load_menu_init();
5876 case GS_STATE_SIMULATOR_ROOM:
5880 case GS_STATE_CAMPAIGN_ROOM:
5881 campaign_room_init();
5884 case GS_STATE_RED_ALERT:
5885 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5889 case GS_STATE_CMD_BRIEF: {
5890 int team_num = 0; // team number used as index for which cmd brief to use.
5892 if (old_state == GS_STATE_OPTIONS_MENU) {
5896 main_hall_stop_music();
5897 main_hall_stop_ambient();
5899 if (Game_mode & GM_NORMAL) {
5900 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5901 // MWA: or from options or hotkey screens
5902 // JH: or if the command brief state already did this
5903 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5904 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5905 if ( !game_start_mission() ) // this should put us into a new state on failure!
5910 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5911 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5912 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5914 cmd_brief_init(team_num);
5920 case GS_STATE_SHIP_SELECT:
5924 case GS_STATE_WEAPON_SELECT:
5925 weapon_select_init();
5928 case GS_STATE_TEAM_SELECT:
5932 case GS_STATE_GAME_PAUSED:
5937 case GS_STATE_DEBUG_PAUSED:
5938 // game_stop_time();
5939 // os_set_title("FreeSpace - PAUSED");
5942 case GS_STATE_TRAINING_PAUSED:
5949 case GS_STATE_OPTIONS_MENU:
5951 options_menu_init();
5954 case GS_STATE_GAME_PLAY:
5955 // coming from the gameplay state or the main menu, we might need to load the mission
5956 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5957 if ( !game_start_mission() ) // this should put us into a new state.
5962 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5963 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5964 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5965 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5966 (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) ) {
5967 // JAS: Used to do all paging here.
5971 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5975 main_hall_stop_music();
5976 main_hall_stop_ambient();
5977 event_music_first_pattern(); // start the first pattern
5980 // special code that restores player ship selection and weapons loadout when doing a quick start
5981 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5982 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5983 wss_direct_restore_loadout();
5987 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5988 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5989 event_music_first_pattern(); // start the first pattern
5992 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5993 event_music_first_pattern(); // start the first pattern
5995 player_restore_target_and_weapon_link_prefs();
5997 Game_mode |= GM_IN_MISSION;
6000 // required to truely make mouse deltas zeroed in debug mouse code
6001 void mouse_force_pos(int x, int y);
6002 if (!Is_standalone) {
6003 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6009 // only start time if in single player, or coming from multi wait state
6012 (Game_mode & GM_NORMAL) &&
6013 (old_state != GS_STATE_VIEW_CUTSCENES)
6015 (Game_mode & GM_MULTIPLAYER) && (
6016 (old_state == GS_STATE_MULTI_PAUSED) ||
6017 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6023 // when coming from the multi paused state, reset the timestamps
6024 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6025 multi_reset_timestamps();
6028 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6029 // initialize all object update details
6030 multi_oo_gameplay_init();
6033 // under certain circumstances, the server should reset the object update rate limiting stuff
6034 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6035 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6037 // reinitialize the rate limiting system for all clients
6038 multi_oo_rate_init_all();
6041 // multiplayer clients should always re-initialize their control info rate limiting system
6042 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6043 multi_oo_rate_init_all();
6047 if(Game_mode & GM_MULTIPLAYER){
6048 multi_ping_reset_players();
6051 Game_subspace_effect = 0;
6052 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6053 Game_subspace_effect = 1;
6054 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6055 game_start_subspace_ambient_sound();
6059 sound_env_set(&Game_sound_env);
6060 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6062 // clear multiplayer button info i
6063 extern button_info Multi_ship_status_bi;
6064 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6067 case GS_STATE_HUD_CONFIG:
6071 case GS_STATE_MULTI_JOIN_GAME:
6072 multi_join_clear_game_list();
6074 if (old_state != GS_STATE_OPTIONS_MENU) {
6075 multi_join_game_init();
6080 case GS_STATE_MULTI_HOST_SETUP:
6081 // don't reinitialize if we're coming back from the host options screen
6082 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6083 multi_create_game_init();
6088 case GS_STATE_MULTI_CLIENT_SETUP:
6089 if (old_state != GS_STATE_OPTIONS_MENU) {
6090 multi_game_client_setup_init();
6095 case GS_STATE_CONTROL_CONFIG:
6096 control_config_init();
6099 case GS_STATE_TECH_MENU:
6103 case GS_STATE_BARRACKS_MENU:
6104 if(old_state != GS_STATE_VIEW_MEDALS){
6109 case GS_STATE_MISSION_LOG_SCROLLBACK:
6110 hud_scrollback_init();
6113 case GS_STATE_DEATH_DIED:
6114 Player_died_time = timestamp(10);
6116 if(!(Game_mode & GM_MULTIPLAYER)){
6117 player_show_death_message();
6119 Game_mode |= GM_DEAD_DIED;
6122 case GS_STATE_DEATH_BLEW_UP:
6123 if ( !popupdead_is_active() ) {
6124 Player_ai->target_objnum = -1;
6127 // stop any local EMP effect
6130 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6131 Game_mode |= GM_DEAD_BLEW_UP;
6132 Show_viewing_from_self = 0;
6134 // timestamp how long we should wait before displaying the died popup
6135 if ( !popupdead_is_active() ) {
6136 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6140 case GS_STATE_GAMEPLAY_HELP:
6141 gameplay_help_init();
6144 case GS_STATE_CREDITS:
6145 main_hall_stop_music();
6146 main_hall_stop_ambient();
6150 case GS_STATE_VIEW_MEDALS:
6151 medal_main_init(Player);
6154 case GS_STATE_SHOW_GOALS:
6155 mission_show_goals_init();
6158 case GS_STATE_HOTKEY_SCREEN:
6159 mission_hotkey_init();
6162 case GS_STATE_MULTI_MISSION_SYNC:
6163 // if we're coming from the options screen, don't do any
6164 if(old_state == GS_STATE_OPTIONS_MENU){
6168 switch(Multi_sync_mode){
6169 case MULTI_SYNC_PRE_BRIEFING:
6170 // if moving from game forming to the team select state
6173 case MULTI_SYNC_POST_BRIEFING:
6174 // if moving from briefing into the mission itself
6177 // tell everyone that we're now loading data
6178 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6179 send_netplayer_update_packet();
6181 // JAS: Used to do all paging here!!!!
6183 Net_player->state = NETPLAYER_STATE_WAITING;
6184 send_netplayer_update_packet();
6186 Game_time_compression = F1_0;
6188 case MULTI_SYNC_INGAME:
6194 case GS_STATE_VIEW_CUTSCENES:
6195 cutscenes_screen_init();
6198 case GS_STATE_MULTI_STD_WAIT:
6199 multi_standalone_wait_init();
6202 case GS_STATE_STANDALONE_MAIN:
6203 // don't initialize if we're coming from one of these 2 states unless there are no
6204 // players left (reset situation)
6205 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6206 standalone_main_init();
6210 case GS_STATE_MULTI_PAUSED:
6214 case GS_STATE_INGAME_PRE_JOIN:
6215 multi_ingame_select_init();
6218 case GS_STATE_STANDALONE_POSTGAME:
6219 multi_standalone_postgame_init();
6222 case GS_STATE_INITIAL_PLAYER_SELECT:
6223 player_select_init();
6226 case GS_STATE_MULTI_START_GAME:
6227 multi_start_game_init();
6230 case GS_STATE_MULTI_HOST_OPTIONS:
6231 multi_host_options_init();
6234 case GS_STATE_END_OF_CAMPAIGN:
6235 mission_campaign_end_init();
6238 case GS_STATE_LOOP_BRIEF:
6245 // do stuff that may need to be done regardless of state
6246 void game_do_state_common(int state,int no_networking)
6248 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6249 snd_do_frame(); // update sound system
6250 event_music_do_frame(); // music needs to play across many states
6252 multi_log_process();
6254 if (no_networking) {
6258 // maybe do a multiplayer frame based on game mode and state type
6259 if (Game_mode & GM_MULTIPLAYER) {
6261 case GS_STATE_OPTIONS_MENU:
6262 case GS_STATE_GAMEPLAY_HELP:
6263 case GS_STATE_HOTKEY_SCREEN:
6264 case GS_STATE_HUD_CONFIG:
6265 case GS_STATE_CONTROL_CONFIG:
6266 case GS_STATE_MISSION_LOG_SCROLLBACK:
6267 case GS_STATE_SHOW_GOALS:
6268 case GS_STATE_VIEW_CUTSCENES:
6269 case GS_STATE_EVENT_DEBUG:
6270 multi_maybe_do_frame();
6274 game_do_networking();
6278 // Called once a frame.
6279 // You should never try to change the state
6280 // in here... if you think you need to, you probably really
6281 // need to post an event, not change the state.
6282 int Game_do_state_should_skip = 0;
6283 void game_do_state(int state)
6285 // always lets the do_state_common() function determine if the state should be skipped
6286 Game_do_state_should_skip = 0;
6288 // legal to set the should skip state anywhere in this function
6289 game_do_state_common(state); // do stuff that may need to be done regardless of state
6291 if(Game_do_state_should_skip){
6296 case GS_STATE_MAIN_MENU:
6297 game_set_frametime(GS_STATE_MAIN_MENU);
6298 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6301 main_hall_do(flFrametime);
6305 case GS_STATE_OPTIONS_MENU:
6306 game_set_frametime(GS_STATE_OPTIONS_MENU);
6307 options_menu_do_frame(flFrametime);
6310 case GS_STATE_BARRACKS_MENU:
6311 game_set_frametime(GS_STATE_BARRACKS_MENU);
6312 barracks_do_frame(flFrametime);
6315 case GS_STATE_TRAINING_MENU:
6316 game_set_frametime(GS_STATE_TRAINING_MENU);
6317 training_menu_do_frame(flFrametime);
6320 case GS_STATE_TECH_MENU:
6321 game_set_frametime(GS_STATE_TECH_MENU);
6322 techroom_do_frame(flFrametime);
6325 case GS_STATE_GAMEPLAY_HELP:
6326 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6327 gameplay_help_do_frame(flFrametime);
6330 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6334 case GS_STATE_GAME_PAUSED:
6338 case GS_STATE_DEBUG_PAUSED:
6340 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6345 case GS_STATE_TRAINING_PAUSED:
6346 game_training_pause_do();
6349 case GS_STATE_LOAD_MISSION_MENU:
6350 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6351 mission_load_menu_do();
6354 case GS_STATE_BRIEFING:
6355 game_set_frametime(GS_STATE_BRIEFING);
6356 brief_do_frame(flFrametime);
6359 case GS_STATE_DEBRIEF:
6360 game_set_frametime(GS_STATE_DEBRIEF);
6361 debrief_do_frame(flFrametime);
6364 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6365 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6366 multi_df_debrief_do();
6369 case GS_STATE_SHIP_SELECT:
6370 game_set_frametime(GS_STATE_SHIP_SELECT);
6371 ship_select_do(flFrametime);
6374 case GS_STATE_WEAPON_SELECT:
6375 game_set_frametime(GS_STATE_WEAPON_SELECT);
6376 weapon_select_do(flFrametime);
6379 case GS_STATE_MISSION_LOG_SCROLLBACK:
6380 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6381 hud_scrollback_do_frame(flFrametime);
6384 case GS_STATE_HUD_CONFIG:
6385 game_set_frametime(GS_STATE_HUD_CONFIG);
6386 hud_config_do_frame(flFrametime);
6389 case GS_STATE_MULTI_JOIN_GAME:
6390 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6391 multi_join_game_do_frame();
6394 case GS_STATE_MULTI_HOST_SETUP:
6395 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6396 multi_create_game_do();
6399 case GS_STATE_MULTI_CLIENT_SETUP:
6400 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6401 multi_game_client_setup_do_frame();
6404 case GS_STATE_CONTROL_CONFIG:
6405 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6406 control_config_do_frame(flFrametime);
6409 case GS_STATE_DEATH_DIED:
6413 case GS_STATE_DEATH_BLEW_UP:
6417 case GS_STATE_SIMULATOR_ROOM:
6418 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6419 sim_room_do_frame(flFrametime);
6422 case GS_STATE_CAMPAIGN_ROOM:
6423 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6424 campaign_room_do_frame(flFrametime);
6427 case GS_STATE_RED_ALERT:
6428 game_set_frametime(GS_STATE_RED_ALERT);
6429 red_alert_do_frame(flFrametime);
6432 case GS_STATE_CMD_BRIEF:
6433 game_set_frametime(GS_STATE_CMD_BRIEF);
6434 cmd_brief_do_frame(flFrametime);
6437 case GS_STATE_CREDITS:
6438 game_set_frametime(GS_STATE_CREDITS);
6439 credits_do_frame(flFrametime);
6442 case GS_STATE_VIEW_MEDALS:
6443 game_set_frametime(GS_STATE_VIEW_MEDALS);
6447 case GS_STATE_SHOW_GOALS:
6448 game_set_frametime(GS_STATE_SHOW_GOALS);
6449 mission_show_goals_do_frame(flFrametime);
6452 case GS_STATE_HOTKEY_SCREEN:
6453 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6454 mission_hotkey_do_frame(flFrametime);
6457 case GS_STATE_VIEW_CUTSCENES:
6458 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6459 cutscenes_screen_do_frame();
6462 case GS_STATE_MULTI_STD_WAIT:
6463 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6464 multi_standalone_wait_do();
6467 case GS_STATE_STANDALONE_MAIN:
6468 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6469 standalone_main_do();
6472 case GS_STATE_MULTI_PAUSED:
6473 game_set_frametime(GS_STATE_MULTI_PAUSED);
6477 case GS_STATE_TEAM_SELECT:
6478 game_set_frametime(GS_STATE_TEAM_SELECT);
6482 case GS_STATE_INGAME_PRE_JOIN:
6483 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6484 multi_ingame_select_do();
6487 case GS_STATE_EVENT_DEBUG:
6489 game_set_frametime(GS_STATE_EVENT_DEBUG);
6490 game_show_event_debug(flFrametime);
6494 case GS_STATE_STANDALONE_POSTGAME:
6495 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6496 multi_standalone_postgame_do();
6499 case GS_STATE_INITIAL_PLAYER_SELECT:
6500 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6504 case GS_STATE_MULTI_MISSION_SYNC:
6505 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6509 case GS_STATE_MULTI_START_GAME:
6510 game_set_frametime(GS_STATE_MULTI_START_GAME);
6511 multi_start_game_do();
6514 case GS_STATE_MULTI_HOST_OPTIONS:
6515 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6516 multi_host_options_do();
6519 case GS_STATE_END_OF_CAMPAIGN:
6520 mission_campaign_end_do();
6523 case GS_STATE_END_DEMO:
6524 game_set_frametime(GS_STATE_END_DEMO);
6525 end_demo_campaign_do();
6528 case GS_STATE_LOOP_BRIEF:
6529 game_set_frametime(GS_STATE_LOOP_BRIEF);
6533 } // end switch(gs_current_state)
6537 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6538 int game_do_ram_check(int ram_in_bytes)
6540 if ( ram_in_bytes < 30*1024*1024 ) {
6541 int allowed_to_run = 1;
6542 if ( ram_in_bytes < 25*1024*1024 ) {
6547 int Freespace_total_ram_MB;
6548 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6550 if ( allowed_to_run ) {
6552 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);
6557 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6558 if ( msgbox_rval == IDCANCEL ) {
6565 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);
6567 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6578 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6579 // If so, copy it over and remove the update directory.
6580 void game_maybe_update_launcher(char *exe_dir)
6583 char src_filename[MAX_PATH];
6584 char dest_filename[MAX_PATH];
6586 strcpy(src_filename, exe_dir);
6587 strcat(src_filename, NOX("\\update\\freespace.exe"));
6589 strcpy(dest_filename, exe_dir);
6590 strcat(dest_filename, NOX("\\freespace.exe"));
6592 // see if src_filename exists
6594 fp = fopen(src_filename, "rb");
6600 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6602 // copy updated freespace.exe to freespace exe dir
6603 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6604 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 );
6608 // delete the file in the update directory
6609 DeleteFile(src_filename);
6611 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6612 char update_dir[MAX_PATH];
6613 strcpy(update_dir, exe_dir);
6614 strcat(update_dir, NOX("\\update"));
6615 RemoveDirectory(update_dir);
6621 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6625 int sub_total_destroyed = 0;
6629 // get the total for all his children
6630 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6631 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6634 // find the # of faces for this _individual_ object
6635 total = submodel_get_num_polys(model_num, sm);
6636 if(strstr(pm->submodel[sm].name, "-destroyed")){
6637 sub_total_destroyed = total;
6641 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6644 *out_total += total + sub_total;
6645 *out_destroyed_total += sub_total_destroyed;
6648 #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);
6649 void game_spew_pof_info()
6651 char *pof_list[1000];
6654 int idx, model_num, i, j;
6656 int total, root_total, model_total, destroyed_total, counted;
6660 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6662 // spew info on all the pofs
6668 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6673 for(idx=0; idx<num_files; idx++, counted++){
6674 sprintf(str, "%s.pof", pof_list[idx]);
6675 model_num = model_load(str, 0, NULL);
6677 pm = model_get(model_num);
6679 // if we have a real model
6684 // go through and print all raw submodels
6685 cfputs("RAW\n", out);
6688 for (i=0; i<pm->n_models; i++) {
6689 total = submodel_get_num_polys(model_num, i);
6691 model_total += total;
6692 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6695 sprintf(str, "Model total %d\n", model_total);
6698 // now go through and do it by LOD
6699 cfputs("BY LOD\n\n", out);
6700 for(i=0; i<pm->n_detail_levels; i++){
6701 sprintf(str, "LOD %d\n", i);
6705 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6707 destroyed_total = 0;
6708 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6709 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6712 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6715 sprintf(str, "TOTAL: %d\n", total + root_total);
6717 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6719 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6722 cfputs("------------------------------------------------------------------------\n\n", out);
6726 if(counted >= MAX_POLYGON_MODELS - 5){
6739 game_spew_pof_info();
6742 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6747 // Don't let more than one instance of Freespace run.
6748 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6750 SetForegroundWindow(hwnd);
6755 // Find out how much RAM is on this machine
6758 ms.dwLength = sizeof(MEMORYSTATUS);
6759 GlobalMemoryStatus(&ms);
6760 Freespace_total_ram = ms.dwTotalPhys;
6762 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6766 if ( ms.dwTotalVirtual < 1024 ) {
6767 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6771 if (!vm_init(24*1024*1024)) {
6772 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 );
6776 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6778 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);
6786 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6787 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6788 seem worth bothering with.
6792 lResult = RegOpenKeyEx(
6793 HKEY_LOCAL_MACHINE, // Where it is
6794 "Software\\Microsoft\\DirectX", // name of key
6795 NULL, // DWORD reserved
6796 KEY_QUERY_VALUE, // Allows all changes
6797 &hKey // Location to store key
6800 if (lResult == ERROR_SUCCESS) {
6802 DWORD dwType, dwLen;
6805 lResult = RegQueryValueEx(
6806 hKey, // Handle to key
6807 "Version", // The values name
6808 NULL, // DWORD reserved
6809 &dwType, // What kind it is
6810 (ubyte *) version, // value to set
6811 &dwLen // How many bytes to set
6814 if (lResult == ERROR_SUCCESS) {
6815 dx_version = atoi(strstr(version, ".") + 1);
6819 DWORD dwType, dwLen;
6822 lResult = RegQueryValueEx(
6823 hKey, // Handle to key
6824 "InstalledVersion", // The values name
6825 NULL, // DWORD reserved
6826 &dwType, // What kind it is
6827 (ubyte *) &val, // value to set
6828 &dwLen // How many bytes to set
6831 if (lResult == ERROR_SUCCESS) {
6839 if (dx_version < 3) {
6840 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6841 "latest version of DirectX at:\n\n"
6842 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6844 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6845 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6850 //=====================================================
6851 // Make sure we're running in the right directory.
6855 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6856 char *p = exe_dir + strlen(exe_dir);
6858 // chop off the filename
6859 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6865 if ( strlen(exe_dir) > 0 ) {
6866 SetCurrentDirectory(exe_dir);
6869 // check for updated freespace.exe
6870 game_maybe_update_launcher(exe_dir);
6878 extern void windebug_memwatch_init();
6879 windebug_memwatch_init();
6883 parse_cmdline(szCmdLine);
6885 #ifdef STANDALONE_ONLY_BUILD
6887 nprintf(("Network", "Standalone running"));
6890 nprintf(("Network", "Standalone running"));
6898 // maybe spew pof stuff
6899 if(Cmdline_spew_pof_info){
6900 game_spew_pof_info();
6905 // non-demo, non-standalone, play the intro movie
6910 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) ){
6912 #if defined(OEM_BUILD)
6913 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6915 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6916 #endif // defined(OEM_BUILD)
6921 if ( !Is_standalone ) {
6923 // release -- movies always play
6926 // 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
6927 movie_play( NOX("intro.mve"), 0 );
6929 // debug version, movie will only play with -showmovies
6930 #elif !defined(NDEBUG)
6932 movie_play( NOX("intro.mve"), 0);
6935 if ( Cmdline_show_movies )
6936 movie_play( NOX("intro.mve"), 0 );
6945 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6947 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6951 // only important for non THREADED mode
6954 state = gameseq_process_events();
6955 if ( state == GS_STATE_QUIT_GAME ){
6962 demo_upsell_show_screens();
6964 #elif defined(OEM_BUILD)
6965 // show upsell screens on exit
6966 oem_upsell_show_screens();
6973 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6979 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6981 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6983 // Do nothing here - RecordExceptionInfo() has already done
6984 // everything that is needed. Actually this code won't even
6985 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6986 // the __except clause.
6990 nprintf(("WinMain", "exceptions shall fall through"));
6992 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6998 // launcher the fslauncher program on exit
6999 void game_launch_launcher_on_exit()
7003 PROCESS_INFORMATION pi;
7004 char cmd_line[2048];
7005 char original_path[1024] = "";
7007 memset( &si, 0, sizeof(STARTUPINFO) );
7011 _getcwd(original_path, 1023);
7013 // set up command line
7014 strcpy(cmd_line, original_path);
7015 strcat(cmd_line, "\\");
7016 strcat(cmd_line, LAUNCHER_FNAME);
7017 strcat(cmd_line, " -straight_to_update");
7019 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7020 cmd_line, // pointer to command line string
7021 NULL, // pointer to process security attributes
7022 NULL, // pointer to thread security attributes
7023 FALSE, // handle inheritance flag
7024 CREATE_DEFAULT_ERROR_MODE, // creation flags
7025 NULL, // pointer to new environment block
7026 NULL, // pointer to current directory name
7027 &si, // pointer to STARTUPINFO
7028 &pi // pointer to PROCESS_INFORMATION
7030 // to eliminate build warnings
7040 // This function is called when FreeSpace terminates normally.
7042 void game_shutdown(void)
7048 // don't ever flip a page on the standalone!
7049 if(!(Game_mode & GM_STANDALONE_SERVER)){
7055 // if the player has left the "player select" screen and quit the game without actually choosing
7056 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7057 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7061 // load up common multiplayer icons
7062 multi_unload_common_icons();
7064 shockwave_close(); // release any memory used by shockwave system
7065 fireball_close(); // free fireball system
7066 ship_close(); // free any memory that was allocated for the ships
7067 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7068 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7069 bm_unload_all(); // free bitmaps
7070 mission_campaign_close(); // close out the campaign stuff
7071 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7073 #ifdef MULTI_USE_LAG
7077 // the menu close functions will unload the bitmaps if they were displayed during the game
7078 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7081 training_menu_close();
7084 extern void joy_close();
7087 audiostream_close();
7089 event_music_close();
7093 // HACKITY HACK HACK
7094 // if this flag is set, we should be firing up the launcher when exiting freespace
7095 extern int Multi_update_fireup_launcher_on_exit;
7096 if(Multi_update_fireup_launcher_on_exit){
7097 game_launch_launcher_on_exit();
7101 // game_stop_looped_sounds()
7103 // This function will call the appropriate stop looped sound functions for those
7104 // modules which use looping sounds. It is not enough just to stop a looping sound
7105 // at the DirectSound level, the game is keeping track of looping sounds, and this
7106 // function is used to inform the game that looping sounds are being halted.
7108 void game_stop_looped_sounds()
7110 hud_stop_looped_locking_sounds();
7111 hud_stop_looped_engine_sounds();
7112 afterburner_stop_sounds();
7113 player_stop_looped_sounds();
7114 obj_snd_stop_all(); // stop all object-linked persistant sounds
7115 game_stop_subspace_ambient_sound();
7116 snd_stop(Radar_static_looping);
7117 Radar_static_looping = -1;
7118 snd_stop(Target_static_looping);
7119 shipfx_stop_engine_wash_sound();
7120 Target_static_looping = -1;
7123 //////////////////////////////////////////////////////////////////////////
7125 // Code for supporting an animating mouse pointer
7128 //////////////////////////////////////////////////////////////////////////
7130 typedef struct animating_obj
7139 static animating_obj Animating_mouse;
7141 // ----------------------------------------------------------------------------
7142 // init_animating_pointer()
7144 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7145 // gets properly initialized
7147 void init_animating_pointer()
7149 Animating_mouse.first_frame = -1;
7150 Animating_mouse.num_frames = 0;
7151 Animating_mouse.current_frame = -1;
7152 Animating_mouse.time = 0.0f;
7153 Animating_mouse.elapsed_time = 0.0f;
7156 // ----------------------------------------------------------------------------
7157 // load_animating_pointer()
7159 // Called at game init to load in the frames for the animating mouse pointer
7161 // input: filename => filename of animation file that holds the animation
7163 void load_animating_pointer(char *filename, int dx, int dy)
7168 init_animating_pointer();
7170 am = &Animating_mouse;
7171 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7172 if ( am->first_frame == -1 )
7173 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7174 am->current_frame = 0;
7175 am->time = am->num_frames / i2fl(fps);
7178 // ----------------------------------------------------------------------------
7179 // unload_animating_pointer()
7181 // Called at game shutdown to free the memory used to store the animation frames
7183 void unload_animating_pointer()
7188 am = &Animating_mouse;
7189 for ( i = 0; i < am->num_frames; i++ ) {
7190 Assert( (am->first_frame+i) >= 0 );
7191 bm_release(am->first_frame + i);
7194 am->first_frame = -1;
7196 am->current_frame = -1;
7199 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7200 void game_render_mouse(float frametime)
7205 // if animating cursor exists, play the next frame
7206 am = &Animating_mouse;
7207 if ( am->first_frame != -1 ) {
7208 mouse_get_pos(&mx, &my);
7209 am->elapsed_time += frametime;
7210 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7211 if ( am->current_frame >= am->num_frames ) {
7212 am->current_frame = 0;
7213 am->elapsed_time = 0.0f;
7215 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7219 // ----------------------------------------------------------------------------
7220 // game_maybe_draw_mouse()
7222 // determines whether to draw the mouse pointer at all, and what frame of
7223 // animation to use if the mouse is animating
7225 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7227 // input: frametime => elapsed frame time in seconds since last call
7229 void game_maybe_draw_mouse(float frametime)
7233 game_state = gameseq_get_state();
7235 switch ( game_state ) {
7236 case GS_STATE_GAME_PAUSED:
7237 // case GS_STATE_MULTI_PAUSED:
7238 case GS_STATE_GAME_PLAY:
7239 case GS_STATE_DEATH_DIED:
7240 case GS_STATE_DEATH_BLEW_UP:
7241 if ( popup_active() || popupdead_is_active() ) {
7253 if ( !Mouse_hidden )
7254 game_render_mouse(frametime);
7258 void game_do_training_checks()
7262 waypoint_list *wplp;
7264 if (Training_context & TRAINING_CONTEXT_SPEED) {
7265 s = (int) Player_obj->phys_info.fspeed;
7266 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7267 if (!Training_context_speed_set) {
7268 Training_context_speed_set = 1;
7269 Training_context_speed_timestamp = timestamp();
7273 Training_context_speed_set = 0;
7276 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7277 wplp = &Waypoint_lists[Training_context_path];
7278 if (wplp->count > Training_context_goal_waypoint) {
7279 i = Training_context_goal_waypoint;
7281 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7282 if (d <= Training_context_distance) {
7283 Training_context_at_waypoint = i;
7284 if (Training_context_goal_waypoint == i) {
7285 Training_context_goal_waypoint++;
7286 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7293 if (i == wplp->count)
7296 } while (i != Training_context_goal_waypoint);
7300 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7301 Players_target = Player_ai->target_objnum;
7302 Players_targeted_subsys = Player_ai->targeted_subsys;
7303 Players_target_timestamp = timestamp();
7307 /////////// Following is for event debug view screen
7311 #define EVENT_DEBUG_MAX 5000
7312 #define EVENT_DEBUG_EVENT 0x8000
7314 int Event_debug_index[EVENT_DEBUG_MAX];
7317 void game_add_event_debug_index(int n, int indent)
7319 if (ED_count < EVENT_DEBUG_MAX)
7320 Event_debug_index[ED_count++] = n | (indent << 16);
7323 void game_add_event_debug_sexp(int n, int indent)
7328 if (Sexp_nodes[n].first >= 0) {
7329 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7330 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7334 game_add_event_debug_index(n, indent);
7335 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7336 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7338 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7341 void game_event_debug_init()
7346 for (e=0; e<Num_mission_events; e++) {
7347 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7348 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7352 void game_show_event_debug(float frametime)
7356 int font_height, font_width;
7358 static int scroll_offset = 0;
7360 k = game_check_key();
7366 if (scroll_offset < 0)
7376 scroll_offset -= 20;
7377 if (scroll_offset < 0)
7382 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7386 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7392 gr_set_color_fast(&Color_bright);
7394 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7396 gr_set_color_fast(&Color_normal);
7398 gr_get_string_size(&font_width, &font_height, NOX("test"));
7399 y_max = gr_screen.max_h - font_height - 5;
7403 while (k < ED_count) {
7404 if (y_index > y_max)
7407 z = Event_debug_index[k];
7408 if (z & EVENT_DEBUG_EVENT) {
7410 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7411 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7412 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7413 Mission_events[z].repeat_count, Mission_events[z].interval);
7421 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7422 switch (Sexp_nodes[z & 0x7fff].value) {
7424 strcat(buf, NOX(" (True)"));
7428 strcat(buf, NOX(" (False)"));
7431 case SEXP_KNOWN_TRUE:
7432 strcat(buf, NOX(" (Always true)"));
7435 case SEXP_KNOWN_FALSE:
7436 strcat(buf, NOX(" (Always false)"));
7439 case SEXP_CANT_EVAL:
7440 strcat(buf, NOX(" (Can't eval)"));
7444 case SEXP_NAN_FOREVER:
7445 strcat(buf, NOX(" (Not a number)"));
7450 gr_printf(10, y_index, buf);
7451 y_index += font_height;
7464 extern int Tmap_npixels;
7466 int Tmap_num_too_big = 0;
7467 int Num_models_needing_splitting = 0;
7469 void Time_model( int modelnum )
7471 // mprintf(( "Timing ship '%s'\n", si->name ));
7473 vector eye_pos, model_pos;
7474 matrix eye_orient, model_orient;
7476 polymodel *pm = model_get( modelnum );
7478 int l = strlen(pm->filename);
7480 if ( (l == '/') || (l=='\\') || (l==':')) {
7486 char *pof_file = &pm->filename[l];
7488 int model_needs_splitting = 0;
7490 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7492 for (i=0; i<pm->n_textures; i++ ) {
7493 char filename[1024];
7496 int bmp_num = pm->original_textures[i];
7497 if ( bmp_num > -1 ) {
7498 bm_get_palette(pm->original_textures[i], pal, filename );
7500 bm_get_info( pm->original_textures[i],&w, &h );
7503 if ( (w > 512) || (h > 512) ) {
7504 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7506 model_needs_splitting++;
7509 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7513 if ( model_needs_splitting ) {
7514 Num_models_needing_splitting++;
7516 eye_orient = model_orient = vmd_identity_matrix;
7517 eye_pos = model_pos = vmd_zero_vector;
7519 eye_pos.xyz.z = -pm->rad*2.0f;
7521 vector eye_to_model;
7523 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7524 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7526 fix t1 = timer_get_fixed_seconds();
7529 ta.p = ta.b = ta.h = 0.0f;
7534 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7536 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7538 modelstats_num_polys = modelstats_num_verts = 0;
7540 while( ta.h < PI2 ) {
7543 vm_angles_2_matrix(&m1, &ta );
7544 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7551 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7553 model_clear_instance( modelnum );
7554 model_set_detail_level(0); // use highest detail level
7555 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7563 int k = key_inkey();
7564 if ( k == KEY_ESC ) {
7569 fix t2 = timer_get_fixed_seconds();
7571 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7572 //bitmaps_used_this_frame /= framecount;
7574 modelstats_num_polys /= framecount;
7575 modelstats_num_verts /= framecount;
7577 Tmap_npixels /=framecount;
7580 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7581 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 );
7582 // 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 );
7588 int Time_models = 0;
7589 DCF_BOOL( time_models, Time_models );
7591 void Do_model_timings_test()
7595 if ( !Time_models ) return;
7597 mprintf(( "Timing models!\n" ));
7601 ubyte model_used[MAX_POLYGON_MODELS];
7602 int model_id[MAX_POLYGON_MODELS];
7603 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7608 for (i=0; i<Num_ship_types; i++ ) {
7609 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7611 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7612 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7615 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7616 if ( !Texture_fp ) return;
7618 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7619 if ( !Time_fp ) return;
7621 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7622 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7624 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7625 if ( model_used[i] ) {
7626 Time_model( model_id[i] );
7630 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7631 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7640 // Call this function when you want to inform the player that a feature is not
7641 // enabled in the DEMO version of FreSpace
7642 void game_feature_not_in_demo_popup()
7644 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7647 // format the specified time (fixed point) into a nice string
7648 void game_format_time(fix m_time,char *time_str)
7651 int hours,minutes,seconds;
7654 mtime = f2fl(m_time);
7656 // get the hours, minutes and seconds
7657 hours = (int)(mtime / 3600.0f);
7659 mtime -= (3600.0f * (float)hours);
7661 seconds = (int)mtime%60;
7662 minutes = (int)mtime/60;
7664 // print the hour if necessary
7666 sprintf(time_str,XSTR( "%d:", 201),hours);
7667 // if there are less than 10 minutes, print a leading 0
7669 strcpy(tmp,NOX("0"));
7670 strcat(time_str,tmp);
7674 // print the minutes
7676 sprintf(tmp,XSTR( "%d:", 201),minutes);
7677 strcat(time_str,tmp);
7679 sprintf(time_str,XSTR( "%d:", 201),minutes);
7682 // print the seconds
7684 strcpy(tmp,NOX("0"));
7685 strcat(time_str,tmp);
7687 sprintf(tmp,"%d",seconds);
7688 strcat(time_str,tmp);
7691 // Stuff version string in *str.
7692 void get_version_string(char *str)
7695 if ( FS_VERSION_BUILD == 0 ) {
7696 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7698 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7701 #if defined (FS2_DEMO)
7703 #elif defined (OEM_BUILD)
7704 strcat(str, " (OEM)");
7710 char myname[_MAX_PATH];
7711 int namelen, major, minor, build, waste;
7712 unsigned int buf_size;
7718 // Find my EXE file name
7719 hMod = GetModuleHandle(NULL);
7720 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7722 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7723 infop = (char *)malloc(version_size);
7724 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7726 // get the product version
7727 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7728 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7730 sprintf(str,"Dv%d.%02d",major, minor);
7732 sprintf(str,"v%d.%02d",major, minor);
7737 void get_version_string_short(char *str)
7739 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7742 // ----------------------------------------------------------------
7744 // OEM UPSELL SCREENS BEGIN
7746 // ----------------------------------------------------------------
7747 #if defined(OEM_BUILD)
7749 #define NUM_OEM_UPSELL_SCREENS 3
7750 #define OEM_UPSELL_SCREEN_DELAY 10000
7752 static int Oem_upsell_bitmaps_loaded = 0;
7753 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7754 static int Oem_upsell_screen_number = 0;
7755 static int Oem_upsell_show_next_bitmap_time;
7758 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7771 static int Oem_normal_cursor = -1;
7772 static int Oem_web_cursor = -1;
7773 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7774 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7776 void oem_upsell_next_screen()
7778 Oem_upsell_screen_number++;
7779 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7780 // extra long delay, mouse shown on last upsell
7781 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7785 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7789 void oem_upsell_load_bitmaps()
7793 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7794 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7798 void oem_upsell_unload_bitmaps()
7802 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7803 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7804 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7809 Oem_upsell_bitmaps_loaded = 0;
7812 // clickable hotspot on 3rd OEM upsell screen
7813 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7815 28, 350, 287, 96 // x, y, w, h
7818 45, 561, 460, 152 // x, y, w, h
7822 void oem_upsell_show_screens()
7824 int current_time, k;
7827 if ( !Oem_upsell_bitmaps_loaded ) {
7828 oem_upsell_load_bitmaps();
7829 Oem_upsell_bitmaps_loaded = 1;
7832 // may use upsell screens more than once
7833 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7834 Oem_upsell_screen_number = 0;
7840 int nframes; // used to pass, not really needed (should be 1)
7841 Oem_normal_cursor = gr_get_cursor_bitmap();
7842 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7843 Assert(Oem_web_cursor >= 0);
7844 if (Oem_web_cursor < 0) {
7845 Oem_web_cursor = Oem_normal_cursor;
7850 //oem_reset_trailer_timer();
7852 current_time = timer_get_milliseconds();
7857 // advance screen on keypress or timeout
7858 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7859 oem_upsell_next_screen();
7862 // check if we are done
7863 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7864 Oem_upsell_screen_number--;
7867 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7872 // show me the upsell
7873 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7874 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7878 // if this is the 3rd upsell, make it clickable, d00d
7879 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7881 int button_state = mouse_get_pos(&mx, &my);
7882 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])
7883 && (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]) )
7886 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7889 if (button_state & MOUSE_LEFT_BUTTON) {
7891 multi_pxo_url(OEM_UPSELL_URL);
7895 // switch cursor back to normal one
7896 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7901 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7911 oem_upsell_unload_bitmaps();
7913 // switch cursor back to normal one
7914 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7918 #endif // defined(OEM_BUILD)
7919 // ----------------------------------------------------------------
7921 // OEM UPSELL SCREENS END
7923 // ----------------------------------------------------------------
7927 // ----------------------------------------------------------------
7929 // DEMO UPSELL SCREENS BEGIN
7931 // ----------------------------------------------------------------
7935 //#define NUM_DEMO_UPSELL_SCREENS 4
7937 #define NUM_DEMO_UPSELL_SCREENS 2
7938 #define DEMO_UPSELL_SCREEN_DELAY 3000
7940 static int Demo_upsell_bitmaps_loaded = 0;
7941 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7942 static int Demo_upsell_screen_number = 0;
7943 static int Demo_upsell_show_next_bitmap_time;
7946 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7959 void demo_upsell_next_screen()
7961 Demo_upsell_screen_number++;
7962 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7963 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7965 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7969 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7970 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7971 #ifndef HARDWARE_ONLY
7972 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7979 void demo_upsell_load_bitmaps()
7983 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7984 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7988 void demo_upsell_unload_bitmaps()
7992 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7993 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7994 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7999 Demo_upsell_bitmaps_loaded = 0;
8002 void demo_upsell_show_screens()
8004 int current_time, k;
8007 if ( !Demo_upsell_bitmaps_loaded ) {
8008 demo_upsell_load_bitmaps();
8009 Demo_upsell_bitmaps_loaded = 1;
8012 // may use upsell screens more than once
8013 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8014 Demo_upsell_screen_number = 0;
8021 demo_reset_trailer_timer();
8023 current_time = timer_get_milliseconds();
8030 // don't time out, wait for keypress
8032 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8033 demo_upsell_next_screen();
8038 demo_upsell_next_screen();
8041 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8042 Demo_upsell_screen_number--;
8045 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8050 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8051 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8056 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8066 demo_upsell_unload_bitmaps();
8071 // ----------------------------------------------------------------
8073 // DEMO UPSELL SCREENS END
8075 // ----------------------------------------------------------------
8078 // ----------------------------------------------------------------
8080 // Subspace Ambient Sound START
8082 // ----------------------------------------------------------------
8084 static int Subspace_ambient_left_channel = -1;
8085 static int Subspace_ambient_right_channel = -1;
8088 void game_start_subspace_ambient_sound()
8090 if ( Subspace_ambient_left_channel < 0 ) {
8091 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8094 if ( Subspace_ambient_right_channel < 0 ) {
8095 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8099 void game_stop_subspace_ambient_sound()
8101 if ( Subspace_ambient_left_channel >= 0 ) {
8102 snd_stop(Subspace_ambient_left_channel);
8103 Subspace_ambient_left_channel = -1;
8106 if ( Subspace_ambient_right_channel >= 0 ) {
8107 snd_stop(Subspace_ambient_right_channel);
8108 Subspace_ambient_right_channel = -1;
8112 // ----------------------------------------------------------------
8114 // Subspace Ambient Sound END
8116 // ----------------------------------------------------------------
8118 // ----------------------------------------------------------------
8120 // CDROM detection code START
8122 // ----------------------------------------------------------------
8124 #define CD_SIZE_72_MINUTE_MAX (697000000)
8126 uint game_get_cd_used_space(char *path)
8130 char use_path[512] = "";
8131 char sub_path[512] = "";
8132 WIN32_FIND_DATA find;
8135 // recurse through all files and directories
8136 strcpy(use_path, path);
8137 strcat(use_path, "*.*");
8138 find_handle = FindFirstFile(use_path, &find);
8141 if(find_handle == INVALID_HANDLE_VALUE){
8147 // subdirectory. make sure to ignore . and ..
8148 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8150 strcpy(sub_path, path);
8151 strcat(sub_path, find.cFileName);
8152 strcat(sub_path, "\\");
8153 total += game_get_cd_used_space(sub_path);
8155 total += (uint)find.nFileSizeLow;
8157 } while(FindNextFile(find_handle, &find));
8160 FindClose(find_handle);
8172 // if volume_name is non-null, the CD name must match that
8173 int find_freespace_cd(char *volume_name)
8176 char oldpath[MAX_PATH];
8180 int volume_match = 0;
8184 GetCurrentDirectory(MAX_PATH, oldpath);
8186 for (i = 0; i < 26; i++)
8192 path[0] = (char)('A'+i);
8193 if (GetDriveType(path) == DRIVE_CDROM) {
8195 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8196 nprintf(("CD", "CD volume: %s\n", volume));
8198 // check for any CD volume
8199 int volume1_present = 0;
8200 int volume2_present = 0;
8201 int volume3_present = 0;
8203 char full_check[512] = "";
8205 // look for setup.exe
8206 strcpy(full_check, path);
8207 strcat(full_check, "setup.exe");
8208 find_handle = _findfirst(full_check, &find);
8209 if(find_handle != -1){
8210 volume1_present = 1;
8211 _findclose(find_handle);
8214 // look for intro.mve
8215 strcpy(full_check, path);
8216 strcat(full_check, "intro.mve");
8217 find_handle = _findfirst(full_check, &find);
8218 if(find_handle != -1){
8219 volume2_present = 1;
8220 _findclose(find_handle);
8223 // look for endpart1.mve
8224 strcpy(full_check, path);
8225 strcat(full_check, "endpart1.mve");
8226 find_handle = _findfirst(full_check, &find);
8227 if(find_handle != -1){
8228 volume3_present = 1;
8229 _findclose(find_handle);
8232 // see if we have the specific CD we're looking for
8233 if ( volume_name ) {
8235 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8239 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8243 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8247 if ( volume1_present || volume2_present || volume3_present ) {
8252 // 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
8253 if ( volume_match ){
8255 // 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
8256 if(volume2_present || volume3_present) {
8257 // first step - check to make sure its a cdrom
8258 if(GetDriveType(path) != DRIVE_CDROM){
8262 #if !defined(OEM_BUILD)
8263 // oem not on 80 min cds, so dont check tha size
8265 uint used_space = game_get_cd_used_space(path);
8266 if(used_space < CD_SIZE_72_MINUTE_MAX){
8269 #endif // !defined(OEM_BUILD)
8277 #endif // RELEASE_REAL
8283 SetCurrentDirectory(oldpath);
8292 int set_cdrom_path(int drive_num)
8296 if (drive_num < 0) { //no CD
8298 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8301 strcpy(Game_CDROM_dir,""); //set directory
8305 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8321 i = find_freespace_cd();
8323 rval = set_cdrom_path(i);
8327 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8329 nprintf(("CD", "FreeSpace CD not found\n"));
8337 int Last_cd_label_found = 0;
8338 char Last_cd_label[256];
8340 int game_cd_changed()
8347 if ( strlen(Game_CDROM_dir) == 0 ) {
8351 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8353 if ( found != Last_cd_label_found ) {
8354 Last_cd_label_found = found;
8356 mprintf(( "CD '%s' was inserted\n", label ));
8359 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8363 if ( Last_cd_label_found ) {
8364 if ( !stricmp( Last_cd_label, label )) {
8365 //mprintf(( "CD didn't change\n" ));
8367 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8371 // none found before, none found now.
8372 //mprintf(( "still no CD...\n" ));
8376 Last_cd_label_found = found;
8378 strcpy( Last_cd_label, label );
8380 strcpy( Last_cd_label, "" );
8391 // check if _any_ FreeSpace2 CDs are in the drive
8392 // return: 1 => CD now in drive
8393 // 0 => Could not find CD, they refuse to put it in the drive
8394 int game_do_cd_check(char *volume_name)
8396 #if !defined(GAME_CD_CHECK)
8402 int num_attempts = 0;
8403 int refresh_files = 0;
8405 int path_set_ok, popup_rval;
8407 cd_drive_num = find_freespace_cd(volume_name);
8408 path_set_ok = set_cdrom_path(cd_drive_num);
8409 if ( path_set_ok ) {
8411 if ( refresh_files ) {
8423 // no CD found, so prompt user
8424 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8426 if ( popup_rval != 1 ) {
8431 if ( num_attempts++ > 5 ) {
8442 // check if _any_ FreeSpace2 CDs are in the drive
8443 // return: 1 => CD now in drive
8444 // 0 => Could not find CD, they refuse to put it in the drive
8445 int game_do_cd_check_specific(char *volume_name, int cdnum)
8450 int num_attempts = 0;
8451 int refresh_files = 0;
8453 int path_set_ok, popup_rval;
8455 cd_drive_num = find_freespace_cd(volume_name);
8456 path_set_ok = set_cdrom_path(cd_drive_num);
8457 if ( path_set_ok ) {
8459 if ( refresh_files ) {
8470 // no CD found, so prompt user
8471 #if defined(DVD_MESSAGE_HACK)
8472 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8474 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8477 if ( popup_rval != 1 ) {
8482 if ( num_attempts++ > 5 ) {
8492 // only need to do this in RELEASE_REAL
8493 int game_do_cd_mission_check(char *filename)
8499 fs_builtin_mission *m = game_find_builtin_mission(filename);
8501 // check for changed CD
8502 if(game_cd_changed()){
8507 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8511 // not builtin, so do a general check (any FS2 CD will do)
8513 return game_do_cd_check();
8516 // does not have any CD requirement, do a general check
8517 if(strlen(m->cd_volume) <= 0){
8518 return game_do_cd_check();
8522 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8524 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8526 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8529 return game_do_cd_check();
8532 // did we find the cd?
8533 if(find_freespace_cd(m->cd_volume) >= 0){
8537 // make sure the volume exists
8538 int num_attempts = 0;
8539 int refresh_files = 0;
8541 int path_set_ok, popup_rval;
8543 cd_drive_num = find_freespace_cd(m->cd_volume);
8544 path_set_ok = set_cdrom_path(cd_drive_num);
8545 if ( path_set_ok ) {
8547 if ( refresh_files ) {
8554 // no CD found, so prompt user
8555 #if defined(DVD_MESSAGE_HACK)
8556 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8558 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8562 if ( popup_rval != 1 ) {
8567 if ( num_attempts++ > 5 ) {
8579 // ----------------------------------------------------------------
8581 // CDROM detection code END
8583 // ----------------------------------------------------------------
8585 // ----------------------------------------------------------------
8586 // SHIPS TBL VERIFICATION STUFF
8589 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8590 #define NUM_SHIPS_TBL_CHECKSUMS 1
8593 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8594 1696074201, // FS2 demo
8598 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8599 -463907578, // US - beta 1
8600 1696074201, // FS2 demo
8603 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8604 // -1022810006, // 1.0 FULL
8605 -1254285366 // 1.2 FULL (German)
8609 void verify_ships_tbl()
8613 Game_ships_tbl_valid = 1;
8619 // detect if the packfile exists
8620 CFILE *detect = cfopen("ships.tbl", "rb");
8621 Game_ships_tbl_valid = 0;
8625 Game_ships_tbl_valid = 0;
8629 // get the long checksum of the file
8631 cfseek(detect, 0, SEEK_SET);
8632 cf_chksum_long(detect, &file_checksum);
8636 // now compare the checksum/filesize against known #'s
8637 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8638 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8639 Game_ships_tbl_valid = 1;
8646 DCF(shipspew, "display the checksum for the current ships.tbl")
8649 CFILE *detect = cfopen("ships.tbl", "rb");
8650 // get the long checksum of the file
8652 cfseek(detect, 0, SEEK_SET);
8653 cf_chksum_long(detect, &file_checksum);
8656 dc_printf("%d", file_checksum);
8659 // ----------------------------------------------------------------
8660 // WEAPONS TBL VERIFICATION STUFF
8663 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8664 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8667 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8668 -266420030, // demo 1
8672 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8673 141718090, // US - beta 1
8674 -266420030, // demo 1
8677 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8678 // 399297860, // 1.0 FULL
8679 -553984927 // 1.2 FULL (german)
8683 void verify_weapons_tbl()
8687 Game_weapons_tbl_valid = 1;
8693 // detect if the packfile exists
8694 CFILE *detect = cfopen("weapons.tbl", "rb");
8695 Game_weapons_tbl_valid = 0;
8699 Game_weapons_tbl_valid = 0;
8703 // get the long checksum of the file
8705 cfseek(detect, 0, SEEK_SET);
8706 cf_chksum_long(detect, &file_checksum);
8710 // now compare the checksum/filesize against known #'s
8711 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8712 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8713 Game_weapons_tbl_valid = 1;
8720 DCF(wepspew, "display the checksum for the current weapons.tbl")
8723 CFILE *detect = cfopen("weapons.tbl", "rb");
8724 // get the long checksum of the file
8726 cfseek(detect, 0, SEEK_SET);
8727 cf_chksum_long(detect, &file_checksum);
8730 dc_printf("%d", file_checksum);
8733 // if the game is running using hacked data
8734 int game_hacked_data()
8737 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8745 void display_title_screen()
8747 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8748 ///int title_bitmap;
8751 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8752 if (title_bitmap == -1) {
8758 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8759 extern void d3d_start_frame();
8765 gr_set_bitmap(title_bitmap);
8772 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8773 extern void d3d_stop_frame();
8781 bm_unload(title_bitmap);
8782 #endif // FS2_DEMO || OEM_BUILD
8785 // return true if the game is running with "low memory", which is less than 48MB
8786 bool game_using_low_mem()
8788 if (Use_low_mem == 0) {