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.23 2002/08/04 02:31:00 relnev
19 * make numlock not overlap with pause
21 * Revision 1.22 2002/08/02 23:07:03 relnev
22 * don't access the mouse in standalone mode
24 * Revision 1.21 2002/07/28 05:05:08 relnev
25 * removed some old stuff
27 * Revision 1.20 2002/07/24 00:20:41 relnev
30 * Revision 1.19 2002/06/17 06:33:08 relnev
31 * ryan's struct patch for gcc 2.95
33 * Revision 1.18 2002/06/16 04:46:33 relnev
34 * set up correct checksums for demo
36 * Revision 1.17 2002/06/09 04:41:17 relnev
37 * added copyright header
39 * Revision 1.16 2002/06/09 03:16:04 relnev
42 * removed unneeded asm, old sdl 2d setup.
44 * fixed crash caused by opengl_get_region.
46 * Revision 1.15 2002/06/05 08:05:28 relnev
47 * stub/warning removal.
49 * reworked the sound code.
51 * Revision 1.14 2002/06/05 04:03:32 relnev
52 * finished cfilesystem.
54 * removed some old code.
56 * fixed mouse save off-by-one.
60 * Revision 1.13 2002/06/02 04:26:34 relnev
63 * Revision 1.12 2002/06/02 00:31:35 relnev
64 * implemented osregistry
66 * Revision 1.11 2002/06/01 09:00:34 relnev
67 * silly debug memmanager
69 * Revision 1.10 2002/06/01 07:12:32 relnev
70 * a few NDEBUG updates.
72 * removed a few warnings.
74 * Revision 1.9 2002/05/31 03:05:59 relnev
77 * Revision 1.8 2002/05/29 02:52:32 theoddone33
78 * Enable OpenGL renderer
80 * Revision 1.7 2002/05/28 08:52:03 relnev
81 * implemented two assembly stubs.
83 * cleaned up a few warnings.
85 * added a little demo hackery to make it progress a little farther.
87 * Revision 1.6 2002/05/28 06:28:20 theoddone33
88 * Filesystem mods, actually reads some data files now
90 * Revision 1.5 2002/05/28 04:07:28 theoddone33
91 * New graphics stubbing arrangement
93 * Revision 1.4 2002/05/27 22:46:52 theoddone33
94 * Remove more undefined symbols
96 * Revision 1.3 2002/05/26 23:31:18 relnev
97 * added a few files that needed to be compiled
99 * freespace.cpp: now compiles
101 * Revision 1.2 2002/05/07 03:16:44 theoddone33
102 * The Great Newline Fix
104 * Revision 1.1.1.1 2002/05/03 03:28:09 root
108 * 201 6/16/00 3:15p Jefff
109 * sim of the year dvd version changes, a few german soty localization
112 * 200 11/03/99 11:06a Jefff
115 * 199 10/26/99 5:07p Jamest
116 * fixed jeffs dumb debug code
118 * 198 10/25/99 5:53p Jefff
119 * call control_config_common_init() on startup
121 * 197 10/14/99 10:18a Daveb
122 * Fixed incorrect CD checking problem on standalone server.
124 * 196 10/13/99 9:22a Daveb
125 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
126 * related to movies. Fixed launcher spawning from PXO screen.
128 * 195 10/06/99 11:05a Jefff
129 * new oem upsell 3 hotspot coords
131 * 194 10/06/99 10:31a Jefff
134 * 193 10/01/99 9:10a Daveb
137 * 192 9/15/99 4:57a Dave
138 * Updated ships.tbl checksum
140 * 191 9/15/99 3:58a Dave
141 * Removed framerate warning at all times.
143 * 190 9/15/99 3:16a Dave
144 * Remove mt-011.fs2 from the builtin mission list.
146 * 189 9/15/99 1:45a Dave
147 * Don't init joystick on standalone. Fixed campaign mode on standalone.
148 * Fixed no-score-report problem in TvT
150 * 188 9/14/99 6:08a Dave
151 * Updated (final) single, multi, and campaign list.
153 * 187 9/14/99 3:26a Dave
154 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
155 * respawn-too-early problem. Made a few crash points safe.
157 * 186 9/13/99 4:52p Dave
160 * 185 9/12/99 8:09p Dave
161 * Fixed problem where skip-training button would cause mission messages
162 * not to get paged out for the current mission.
164 * 184 9/10/99 11:53a Dave
165 * Shutdown graphics before sound to eliminate apparent lockups when
166 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
168 * 183 9/09/99 11:40p Dave
169 * Handle an Assert() in beam code. Added supernova sounds. Play the right
170 * 2 end movies properly, based upon what the player did in the mission.
172 * 182 9/08/99 10:29p Dave
173 * Make beam sound pausing and unpausing much safer.
175 * 181 9/08/99 10:01p Dave
176 * Make sure game won't run in a drive's root directory. Make sure
177 * standalone routes suqad war messages properly to the host.
179 * 180 9/08/99 3:22p Dave
180 * Updated builtin mission list.
182 * 179 9/08/99 12:01p Jefff
183 * fixed Game_builtin_mission_list typo on Training-2.fs2
185 * 178 9/08/99 9:48a Andsager
186 * Add force feedback for engine wash.
188 * 177 9/07/99 4:01p Dave
189 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
190 * does everything properly (setting up address when binding). Remove
191 * black rectangle background from UI_INPUTBOX.
193 * 176 9/13/99 2:40a Dave
194 * Comment in full 80 minute CD check for RELEASE_REAL builds.
196 * 175 9/06/99 6:38p Dave
197 * Improved CD detection code.
199 * 174 9/06/99 1:30a Dave
200 * Intermediate checkin. Started on enforcing CD-in-drive to play the
203 * 173 9/06/99 1:16a Dave
204 * Make sure the user sees the intro movie.
206 * 172 9/04/99 8:00p Dave
207 * Fixed up 1024 and 32 bit movie support.
209 * 171 9/03/99 1:32a Dave
210 * CD checking by act. Added support to play 2 cutscenes in a row
211 * seamlessly. Fixed super low level cfile bug related to files in the
212 * root directory of a CD. Added cheat code to set campaign mission # in
215 * 170 9/01/99 10:49p Dave
216 * Added nice SquadWar checkbox to the client join wait screen.
218 * 169 9/01/99 10:14a Dave
221 * 168 8/29/99 4:51p Dave
222 * Fixed damaged checkin.
224 * 167 8/29/99 4:18p Andsager
225 * New "burst" limit for friendly damage. Also credit more damage done
226 * against large friendly ships.
228 * 166 8/27/99 6:38p Alanl
229 * crush the blasted repeating messages bug
231 * 164 8/26/99 9:09p Dave
232 * Force framerate check in everything but a RELEASE_REAL build.
234 * 163 8/26/99 9:45a Dave
235 * First pass at easter eggs and cheats.
237 * 162 8/24/99 8:55p Dave
238 * Make sure nondimming pixels work properly in tech menu.
240 * 161 8/24/99 1:49a Dave
241 * Fixed client-side afterburner stuttering. Added checkbox for no version
242 * checking on PXO join. Made button info passing more friendly between
245 * 160 8/22/99 5:53p Dave
246 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
247 * instead of ship designations for multiplayer players.
249 * 159 8/22/99 1:19p Dave
250 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
251 * which d3d cards are detected.
253 * 158 8/20/99 2:09p Dave
254 * PXO banner cycling.
256 * 157 8/19/99 10:59a Dave
257 * Packet loss detection.
259 * 156 8/19/99 10:12a Alanl
260 * preload mission-specific messages on machines greater than 48MB
262 * 155 8/16/99 4:04p Dave
263 * Big honking checkin.
265 * 154 8/11/99 5:54p Dave
266 * Fixed collision problem. Fixed standalone ghost problem.
268 * 153 8/10/99 7:59p Jefff
271 * 152 8/10/99 6:54p Dave
272 * Mad optimizations. Added paging to the nebula effect.
274 * 151 8/10/99 3:44p Jefff
275 * loads Intelligence information on startup
277 * 150 8/09/99 3:47p Dave
278 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
279 * non-nebula missions.
281 * 149 8/09/99 2:21p Andsager
282 * Fix patching from multiplayer direct to launcher update tab.
284 * 148 8/09/99 10:36a Dave
285 * Version info for game.
287 * 147 8/06/99 9:46p Dave
288 * Hopefully final changes for the demo.
290 * 146 8/06/99 3:34p Andsager
291 * Make title version info "(D)" -> "D" show up nicely
293 * 145 8/06/99 2:59p Adamp
294 * Fixed NT launcher/update problem.
296 * 144 8/06/99 1:52p Dave
297 * Bumped up MAX_BITMAPS for the demo.
299 * 143 8/06/99 12:17p Andsager
300 * Demo: down to just 1 demo dog
302 * 142 8/05/99 9:39p Dave
303 * Yet another new checksum.
305 * 141 8/05/99 6:19p Dave
306 * New demo checksums.
308 * 140 8/05/99 5:31p Andsager
309 * Up demo version 1.01
311 * 139 8/05/99 4:22p Andsager
312 * No time limit on upsell screens. Reverse order of display of upsell
315 * 138 8/05/99 4:17p Dave
316 * Tweaks to client interpolation.
318 * 137 8/05/99 3:52p Danw
320 * 136 8/05/99 3:01p Danw
322 * 135 8/05/99 2:43a Anoop
323 * removed duplicate definition.
325 * 134 8/05/99 2:13a Dave
328 * 133 8/05/99 2:05a Dave
331 * 132 8/05/99 1:22a Andsager
334 * 131 8/04/99 9:51p Andsager
335 * Add title screen to demo
337 * 130 8/04/99 6:47p Jefff
338 * fixed link error resulting from #ifdefs
340 * 129 8/04/99 6:26p Dave
341 * Updated ship tbl checksum.
343 * 128 8/04/99 5:40p Andsager
344 * Add multiple demo dogs
346 * 127 8/04/99 5:36p Andsager
347 * Show upsell screens at end of demo campaign before returning to main
350 * 126 8/04/99 11:42a Danw
351 * tone down EAX reverb
353 * 125 8/04/99 11:23a Dave
354 * Updated demo checksums.
356 * 124 8/03/99 11:02p Dave
357 * Maybe fixed sync problems in multiplayer.
359 * 123 8/03/99 6:21p Jefff
362 * 122 8/03/99 3:44p Andsager
363 * Launch laucher if trying to run FS without first having configured
366 * 121 8/03/99 12:45p Dave
369 * 120 8/02/99 9:13p Dave
372 * 119 7/30/99 10:31p Dave
373 * Added comm menu to the configurable hud files.
375 * 118 7/30/99 5:17p Andsager
376 * first fs2demo checksums
378 * 117 7/29/99 3:09p Anoop
380 * 116 7/29/99 12:05a Dave
381 * Nebula speed optimizations.
383 * 115 7/27/99 8:59a Andsager
384 * Make major, minor version consistent for all builds. Only show major
385 * and minor for launcher update window.
387 * 114 7/26/99 5:50p Dave
388 * Revised ingame join. Better? We'll see....
390 * 113 7/26/99 5:27p Andsager
391 * Add training mission as builtin to demo build
393 * 112 7/24/99 1:54p Dave
394 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
397 * 111 7/22/99 4:00p Dave
398 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
400 * 110 7/21/99 8:10p Dave
401 * First run of supernova effect.
403 * 109 7/20/99 1:49p Dave
404 * Peter Drake build. Fixed some release build warnings.
406 * 108 7/19/99 2:26p Andsager
407 * set demo multiplayer missions
409 * 107 7/18/99 5:19p Dave
410 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
412 * 106 7/16/99 1:50p Dave
413 * 8 bit aabitmaps. yay.
415 * 105 7/15/99 3:07p Dave
416 * 32 bit detection support. Mouse coord commandline.
418 * 104 7/15/99 2:13p Dave
419 * Added 32 bit detection.
421 * 103 7/15/99 9:20a Andsager
422 * FS2_DEMO initial checkin
424 * 102 7/14/99 11:02a Dave
425 * Skill level default back to easy. Blech.
427 * 101 7/09/99 5:54p Dave
428 * Seperated cruiser types into individual types. Added tons of new
429 * briefing icons. Campaign screen.
431 * 100 7/08/99 4:43p Andsager
432 * New check for sparky_hi and print if not found.
434 * 99 7/08/99 10:53a Dave
435 * New multiplayer interpolation scheme. Not 100% done yet, but still
436 * better than the old way.
438 * 98 7/06/99 4:24p Dave
439 * Mid-level checkin. Starting on some potentially cool multiplayer
442 * 97 7/06/99 3:35p Andsager
443 * Allow movie to play before red alert mission.
445 * 96 7/03/99 5:50p Dave
446 * Make rotated bitmaps draw properly in padlock views.
448 * 95 7/02/99 9:55p Dave
449 * Player engine wash sound.
451 * 94 7/02/99 4:30p Dave
452 * Much more sophisticated lightning support.
454 * 93 6/29/99 7:52p Dave
455 * Put in exception handling in FS2.
457 * 92 6/22/99 9:37p Dave
458 * Put in pof spewing.
460 * 91 6/16/99 4:06p Dave
461 * New pilot info popup. Added new draw-bitmap-as-poly function.
463 * 90 6/15/99 1:56p Andsager
464 * For release builds, allow start up in high res only with
467 * 89 6/15/99 9:34a Dave
468 * Fixed key checking in single threaded version of the stamp notification
471 * 88 6/09/99 2:55p Andsager
472 * Allow multiple asteroid subtypes (of large, medium, small) and follow
475 * 87 6/08/99 1:14a Dave
476 * Multi colored hud test.
478 * 86 6/04/99 9:52a Dave
479 * Fixed some rendering problems.
481 * 85 6/03/99 10:15p Dave
482 * Put in temporary main hall screen.
484 * 84 6/02/99 6:18p Dave
485 * Fixed TNT lockup problems! Wheeeee!
487 * 83 6/01/99 3:52p Dave
488 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
489 * dead popup, pxo find player popup, pxo private room popup.
491 * 82 5/26/99 1:28p Jasenw
492 * changed coords for loading ani
494 * 81 5/26/99 11:46a Dave
495 * Added ship-blasting lighting and made the randomization of lighting
496 * much more customizable.
498 * 80 5/24/99 5:45p Dave
499 * Added detail levels to the nebula, with a decent speedup. Split nebula
500 * lightning into its own section.
518 #include "systemvars.h"
523 #include "starfield.h"
524 #include "lighting.h"
529 #include "fireballs.h"
533 #include "floating.h"
534 #include "gamesequence.h"
536 #include "optionsmenu.h"
537 #include "playermenu.h"
538 #include "trainingmenu.h"
539 #include "techmenu.h"
542 #include "hudmessage.h"
544 #include "missiongoals.h"
545 #include "missionparse.h"
550 #include "multiutil.h"
551 #include "multimsgs.h"
555 #include "freespace.h"
556 #include "managepilot.h"
558 #include "contexthelp.h"
561 #include "missionbrief.h"
562 #include "missiondebrief.h"
564 #include "missionshipchoice.h"
566 #include "hudconfig.h"
567 #include "controlsconfig.h"
568 #include "missionmessage.h"
569 #include "missiontraining.h"
571 #include "hudtarget.h"
573 #include "eventmusic.h"
574 #include "animplay.h"
575 #include "missionweaponchoice.h"
576 #include "missionlog.h"
577 #include "audiostr.h"
579 #include "missioncampaign.h"
581 #include "missionhotkey.h"
582 #include "objectsnd.h"
583 #include "cmeasure.h"
585 #include "linklist.h"
586 #include "shockwave.h"
587 #include "afterburner.h"
592 #include "stand_gui.h"
593 #include "pcxutils.h"
594 #include "hudtargetbox.h"
595 #include "multi_xfer.h"
596 #include "hudescort.h"
597 #include "multiutil.h"
600 #include "multiteamselect.h"
603 #include "readyroom.h"
604 #include "mainhallmenu.h"
605 #include "multilag.h"
607 #include "particle.h"
609 #include "multi_ingame.h"
610 #include "snazzyui.h"
611 #include "asteroid.h"
612 #include "popupdead.h"
613 #include "multi_voice.h"
614 #include "missioncmdbrief.h"
615 #include "redalert.h"
616 #include "gameplayhelp.h"
617 #include "multilag.h"
618 #include "staticrand.h"
619 #include "multi_pmsg.h"
620 #include "levelpaging.h"
621 #include "observer.h"
622 #include "multi_pause.h"
623 #include "multi_endgame.h"
624 #include "cutscenes.h"
625 #include "multi_respawn.h"
627 #include "multi_obj.h"
628 #include "multi_log.h"
630 #include "localize.h"
631 #include "osregistry.h"
632 #include "barracks.h"
633 #include "missionpause.h"
635 #include "alphacolors.h"
636 #include "objcollide.h"
639 #include "neblightning.h"
640 #include "shipcontrails.h"
643 #include "multi_dogfight.h"
644 #include "multi_rate.h"
645 #include "muzzleflash.h"
649 #include "mainhalltemp.h"
650 #include "exceptionhandler.h"
654 #include "supernova.h"
655 #include "hudshield.h"
656 // #include "names.h"
658 #include "missionloopbrief.h"
662 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
668 // 1.00.04 5/26/98 MWA -- going final (12 pm)
669 // 1.00.03 5/26/98 MWA -- going final (3 am)
670 // 1.00.02 5/25/98 MWA -- going final
671 // 1.00.01 5/25/98 MWA -- going final
672 // 0.90 5/21/98 MWA -- getting ready for final.
673 // 0.10 4/9/98. Set by MK.
675 // Demo version: (obsolete since DEMO codebase split from tree)
676 // 0.03 4/10/98 AL. Interplay rev
677 // 0.02 4/8/98 MK. Increased when this system was modified.
678 // 0.01 4/7/98? AL. First release to Interplay QA.
681 // 1.00 5/28/98 AL. First release to Interplay QA.
683 void game_level_init(int seed = -1);
684 void game_post_level_init();
685 void game_do_frame();
686 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
687 void game_reset_time();
688 void game_show_framerate(); // draws framerate in lower right corner
690 int Game_no_clear = 0;
692 int Pofview_running = 0;
693 int Nebedit_running = 0;
695 typedef struct big_expl_flash {
696 float max_flash_intensity; // max intensity
697 float cur_flash_intensity; // cur intensity
698 int flash_start; // start time
701 #define FRAME_FILTER 16
703 #define DEFAULT_SKILL_LEVEL 1
704 int Game_skill_level = DEFAULT_SKILL_LEVEL;
706 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
707 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
709 #define EXE_FNAME ("fs2.exe")
710 #define LAUNCHER_FNAME ("freespace2.exe")
712 // JAS: Code for warphole camera.
713 // Needs to be cleaned up.
714 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
715 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
716 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
717 matrix Camera_orient = IDENTITY_MATRIX;
718 float Camera_damping = 1.0f;
719 float Camera_time = 0.0f;
720 float Warpout_time = 0.0f;
721 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
722 int Warpout_sound = -1;
724 int Use_joy_mouse = 0;
725 int Use_palette_flash = 1;
727 int Use_fullscreen_at_startup = 0;
729 int Show_area_effect = 0;
730 object *Last_view_target = NULL;
732 int dogfight_blown = 0;
735 float frametimes[FRAME_FILTER];
736 float frametotal = 0.0f;
740 int Show_framerate = 0;
742 int Show_framerate = 1;
745 int Framerate_cap = 120;
748 int Show_target_debug_info = 0;
749 int Show_target_weapons = 0;
753 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
756 int Debug_octant = -1;
758 fix Game_time_compression = F1_0;
760 // if the ships.tbl the player has is valid
761 int Game_ships_tbl_valid = 0;
763 // if the weapons.tbl the player has is valid
764 int Game_weapons_tbl_valid = 0;
768 extern int Player_attacking_enabled;
772 int Pre_player_entry;
774 int Fred_running = 0;
775 char Game_current_mission_filename[MAX_FILENAME_LEN];
776 int game_single_step = 0;
777 int last_single_step=0;
779 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
780 extern int MSG_WINDOW_Y_START;
781 extern int MSG_WINDOW_HEIGHT;
783 int game_zbuffer = 1;
784 //static int Game_music_paused;
785 static int Game_paused;
789 #define EXPIRE_BAD_CHECKSUM 1
790 #define EXPIRE_BAD_TIME 2
792 extern void ssm_init();
793 extern void ssm_level_init();
794 extern void ssm_process();
796 // static variable to contain the time this version was built
797 // commented out for now until
798 // I figure out how to get the username into the file
799 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
801 // defines and variables used for dumping frame for making trailers.
803 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
804 int Debug_dump_trigger = 0;
805 int Debug_dump_frame_count;
806 int Debug_dump_frame_num = 0;
807 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
810 // amount of time to wait after the player has died before we display the death died popup
811 #define PLAYER_DIED_POPUP_WAIT 2500
812 int Player_died_popup_wait = -1;
813 int Player_multi_died_check = -1;
815 // builtin mission list stuff
817 int Game_builtin_mission_count = 6;
818 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
819 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
820 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
821 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
822 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
823 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
824 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
826 #elif defined(PD_BUILD)
827 int Game_builtin_mission_count = 4;
828 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
829 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
830 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
831 { "sm1-01", (FSB_FROM_VOLITION), "" },
832 { "sm1-05", (FSB_FROM_VOLITION), "" },
834 #elif defined(MULTIPLAYER_BETA)
835 int Game_builtin_mission_count = 17;
836 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
838 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
841 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
845 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
846 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
847 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
848 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
849 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
851 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
852 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
853 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
854 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
856 #elif defined(OEM_BUILD)
857 int Game_builtin_mission_count = 17;
858 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
859 // oem version - act 1 only
860 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
863 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
866 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
869 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
870 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
871 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
872 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
873 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
874 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
875 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
876 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
877 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
878 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
881 int Game_builtin_mission_count = 92;
882 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
883 // single player campaign
884 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
887 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
896 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
899 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
900 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
901 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
902 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
903 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
904 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
905 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
908 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
909 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
911 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
912 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
922 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
925 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
926 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
927 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
928 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
929 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
930 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
931 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
933 // multiplayer missions
936 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
981 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
984 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
985 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
986 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
989 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
990 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
991 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
992 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
993 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
998 // Internal function prototypes
999 void game_maybe_draw_mouse(float frametime);
1000 void init_animating_pointer();
1001 void load_animating_pointer(char *filename, int dx, int dy);
1002 void unload_animating_pointer();
1003 void game_do_training_checks();
1004 void game_shutdown(void);
1005 void game_show_event_debug(float frametime);
1006 void game_event_debug_init();
1008 void demo_upsell_show_screens();
1009 void game_start_subspace_ambient_sound();
1010 void game_stop_subspace_ambient_sound();
1011 void verify_ships_tbl();
1012 void verify_weapons_tbl();
1013 void display_title_screen();
1015 // loading background filenames
1016 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1017 "LoadingBG", // GR_640
1018 "2_LoadingBG" // GR_1024
1022 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1023 "Loading.ani", // GR_640
1024 "2_Loading.ani" // GR_1024
1027 #if defined(FS2_DEMO)
1028 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1032 #elif defined(OEM_BUILD)
1033 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1040 char Game_CDROM_dir[MAX_PATH_LEN];
1043 // How much RAM is on this machine. Set in WinMain
1044 uint Freespace_total_ram = 0;
1047 float Game_flash_red = 0.0f;
1048 float Game_flash_green = 0.0f;
1049 float Game_flash_blue = 0.0f;
1050 float Sun_spot = 0.0f;
1051 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1053 // game shudder stuff (in ms)
1054 int Game_shudder_time = -1;
1055 int Game_shudder_total = 0;
1056 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1059 sound_env Game_sound_env;
1060 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1061 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1063 int Game_sound_env_update_timestamp;
1065 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1068 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1070 fs_builtin_mission *game_find_builtin_mission(char *filename)
1074 // look through all existing builtin missions
1075 for(idx=0; idx<Game_builtin_mission_count; idx++){
1076 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1077 return &Game_builtin_mission_list[idx];
1085 int game_get_default_skill_level()
1087 return DEFAULT_SKILL_LEVEL;
1091 void game_flash_reset()
1093 Game_flash_red = 0.0f;
1094 Game_flash_green = 0.0f;
1095 Game_flash_blue = 0.0f;
1097 Big_expl_flash.max_flash_intensity = 0.0f;
1098 Big_expl_flash.cur_flash_intensity = 0.0f;
1099 Big_expl_flash.flash_start = 0;
1102 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1103 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1105 void game_framerate_check_init()
1107 // zero critical time
1108 Gf_critical_time = 0.0f;
1111 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1112 // if this is a glide card
1113 if(gr_screen.mode == GR_GLIDE){
1115 extern GrHwConfiguration hwconfig;
1118 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1119 Gf_critical = 15.0f;
1123 Gf_critical = 10.0f;
1128 Gf_critical = 15.0f;
1131 // d3d. only care about good cards here I guess (TNT)
1133 Gf_critical = 15.0f;
1136 // if this is a glide card
1137 if(gr_screen.mode == GR_GLIDE){
1139 extern GrHwConfiguration hwconfig;
1142 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1143 Gf_critical = 25.0f;
1147 Gf_critical = 20.0f;
1152 Gf_critical = 25.0f;
1155 // d3d. only care about good cards here I guess (TNT)
1157 Gf_critical = 25.0f;
1162 extern float Framerate;
1163 void game_framerate_check()
1167 // if the current framerate is above the critical level, add frametime
1168 if(Framerate >= Gf_critical){
1169 Gf_critical_time += flFrametime;
1172 if(!Show_framerate){
1176 // display if we're above the critical framerate
1177 if(Framerate < Gf_critical){
1178 gr_set_color_fast(&Color_bright_red);
1179 gr_string(200, y_start, "Framerate warning");
1184 // display our current pct of good frametime
1185 if(f2fl(Missiontime) >= 0.0f){
1186 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1189 gr_set_color_fast(&Color_bright_green);
1191 gr_set_color_fast(&Color_bright_red);
1194 gr_printf(200, y_start, "%d%%", (int)pct);
1201 // Adds a flash effect. These can be positive or negative.
1202 // The range will get capped at around -1 to 1, so stick
1203 // with a range like that.
1204 void game_flash( float r, float g, float b )
1206 Game_flash_red += r;
1207 Game_flash_green += g;
1208 Game_flash_blue += b;
1210 if ( Game_flash_red < -1.0f ) {
1211 Game_flash_red = -1.0f;
1212 } else if ( Game_flash_red > 1.0f ) {
1213 Game_flash_red = 1.0f;
1216 if ( Game_flash_green < -1.0f ) {
1217 Game_flash_green = -1.0f;
1218 } else if ( Game_flash_green > 1.0f ) {
1219 Game_flash_green = 1.0f;
1222 if ( Game_flash_blue < -1.0f ) {
1223 Game_flash_blue = -1.0f;
1224 } else if ( Game_flash_blue > 1.0f ) {
1225 Game_flash_blue = 1.0f;
1230 // Adds a flash for Big Ship explosions
1231 // cap range from 0 to 1
1232 void big_explosion_flash(float flash)
1234 Big_expl_flash.flash_start = timestamp(1);
1238 } else if (flash < 0.0f) {
1242 Big_expl_flash.max_flash_intensity = flash;
1243 Big_expl_flash.cur_flash_intensity = 0.0f;
1246 // Amount to diminish palette towards normal, per second.
1247 #define DIMINISH_RATE 0.75f
1248 #define SUN_DIMINISH_RATE 6.00f
1252 float sn_glare_scale = 1.7f;
1255 dc_get_arg(ARG_FLOAT);
1256 sn_glare_scale = Dc_arg_float;
1259 float Supernova_last_glare = 0.0f;
1260 void game_sunspot_process(float frametime)
1264 float Sun_spot_goal = 0.0f;
1267 sn_stage = supernova_active();
1269 // sunspot differently based on supernova stage
1271 // approaching. player still in control
1274 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1277 light_get_global_dir(&light_dir, 0);
1279 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1282 // scale it some more
1283 dot = dot * (0.5f + (pct * 0.5f));
1286 Sun_spot_goal += (dot * sn_glare_scale);
1289 // draw the sun glow
1290 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1291 // draw the glow for this sun
1292 stars_draw_sun_glow(0);
1295 Supernova_last_glare = Sun_spot_goal;
1298 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1301 Sun_spot_goal = 0.9f;
1302 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1304 if(Sun_spot_goal > 1.0f){
1305 Sun_spot_goal = 1.0f;
1308 Sun_spot_goal *= sn_glare_scale;
1309 Supernova_last_glare = Sun_spot_goal;
1312 // fade to white. display dead popup
1315 Supernova_last_glare += (2.0f * flFrametime);
1316 if(Supernova_last_glare > 2.0f){
1317 Supernova_last_glare = 2.0f;
1320 Sun_spot_goal = Supernova_last_glare;
1327 // check sunspots for all suns
1328 n_lights = light_get_global_count();
1331 for(idx=0; idx<n_lights; idx++){
1332 //(vector *eye_pos, matrix *eye_orient)
1333 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1336 light_get_global_dir(&light_dir, idx);
1338 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1340 Sun_spot_goal += (float)pow(dot,85.0f);
1342 // draw the glow for this sun
1343 stars_draw_sun_glow(idx);
1345 Sun_spot_goal = 0.0f;
1351 Sun_spot_goal = 0.0f;
1355 float dec_amount = frametime*SUN_DIMINISH_RATE;
1357 if ( Sun_spot < Sun_spot_goal ) {
1358 Sun_spot += dec_amount;
1359 if ( Sun_spot > Sun_spot_goal ) {
1360 Sun_spot = Sun_spot_goal;
1362 } else if ( Sun_spot > Sun_spot_goal ) {
1363 Sun_spot -= dec_amount;
1364 if ( Sun_spot < Sun_spot_goal ) {
1365 Sun_spot = Sun_spot_goal;
1371 // Call once a frame to diminish the
1372 // flash effect to 0.
1373 void game_flash_diminish(float frametime)
1375 float dec_amount = frametime*DIMINISH_RATE;
1377 if ( Game_flash_red > 0.0f ) {
1378 Game_flash_red -= dec_amount;
1379 if ( Game_flash_red < 0.0f )
1380 Game_flash_red = 0.0f;
1382 Game_flash_red += dec_amount;
1383 if ( Game_flash_red > 0.0f )
1384 Game_flash_red = 0.0f;
1387 if ( Game_flash_green > 0.0f ) {
1388 Game_flash_green -= dec_amount;
1389 if ( Game_flash_green < 0.0f )
1390 Game_flash_green = 0.0f;
1392 Game_flash_green += dec_amount;
1393 if ( Game_flash_green > 0.0f )
1394 Game_flash_green = 0.0f;
1397 if ( Game_flash_blue > 0.0f ) {
1398 Game_flash_blue -= dec_amount;
1399 if ( Game_flash_blue < 0.0f )
1400 Game_flash_blue = 0.0f;
1402 Game_flash_blue += dec_amount;
1403 if ( Game_flash_blue > 0.0f )
1404 Game_flash_blue = 0.0f;
1407 // update big_explosion_cur_flash
1408 #define TIME_UP 1500
1409 #define TIME_DOWN 2500
1410 int duration = TIME_UP + TIME_DOWN;
1411 int time = timestamp_until(Big_expl_flash.flash_start);
1412 if (time > -duration) {
1414 if (time < TIME_UP) {
1415 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1418 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1422 if ( Use_palette_flash ) {
1424 // static int or=0, og=0, ob=0;
1426 // Change the 200 to change the color range of colors.
1427 r = fl2i( Game_flash_red*128.0f );
1428 g = fl2i( Game_flash_green*128.0f );
1429 b = fl2i( Game_flash_blue*128.0f );
1431 if ( Sun_spot > 0.0f ) {
1432 r += fl2i(Sun_spot*128.0f);
1433 g += fl2i(Sun_spot*128.0f);
1434 b += fl2i(Sun_spot*128.0f);
1437 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1438 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1439 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1440 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1443 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1444 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1445 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1447 if ( (r!=0) || (g!=0) || (b!=0) ) {
1448 gr_flash( r, g, b );
1450 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1461 void game_level_close()
1463 // De-Initialize the game subsystems
1464 message_mission_shutdown();
1465 event_music_level_close();
1466 game_stop_looped_sounds();
1468 obj_snd_level_close(); // uninit object-linked persistant sounds
1469 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1470 anim_level_close(); // stop and clean up any anim instances
1471 shockwave_level_close();
1472 fireball_level_close();
1474 mission_event_shutdown();
1475 asteroid_level_close();
1476 model_cache_reset(); // Reset/free all the model caching stuff
1477 flak_level_close(); // unload flak stuff
1478 neb2_level_close(); // shutdown gaseous nebula stuff
1481 mflash_level_close();
1483 audiostream_unpause_all();
1488 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1489 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1490 void game_level_init(int seed)
1492 // seed the random number generator
1494 // if no seed was passed, seed the generator either from the time value, or from the
1495 // netgame security flags -- ensures that all players in multiplayer game will have the
1496 // same randon number sequence (with static rand functions)
1497 if ( Game_mode & GM_NORMAL ) {
1498 Game_level_seed = time(NULL);
1500 Game_level_seed = Netgame.security;
1503 // mwa 9/17/98 -- maybe this assert isn't needed????
1504 Assert( !(Game_mode & GM_MULTIPLAYER) );
1505 Game_level_seed = seed;
1507 srand( Game_level_seed );
1509 // semirand function needs to get re-initted every time in multiplayer
1510 if ( Game_mode & GM_MULTIPLAYER ){
1516 Key_normal_game = (Game_mode & GM_NORMAL);
1519 Game_shudder_time = -1;
1521 // Initialize the game subsystems
1522 // timestamp_reset(); // Must be inited before everything else
1524 game_reset_time(); // resets time, and resets saved time too
1526 obj_init(); // Must be inited before the other systems
1527 model_free_all(); // Free all existing models
1528 mission_brief_common_init(); // Free all existing briefing/debriefing text
1529 weapon_level_init();
1530 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1532 player_level_init();
1533 shipfx_flash_init(); // Init the ship gun flash system.
1534 game_flash_reset(); // Reset the flash effect
1535 particle_init(); // Reset the particle system
1539 shield_hit_init(); // Initialize system for showing shield hits
1540 radar_mission_init();
1541 mission_init_goals();
1544 obj_snd_level_init(); // init object-linked persistant sounds
1546 shockwave_level_init();
1547 afterburner_level_init();
1548 scoring_level_init( &Player->stats );
1550 asteroid_level_init();
1551 control_config_clear_used_status();
1552 collide_ship_ship_sounds_init();
1554 Pre_player_entry = 1; // Means the player has not yet entered.
1555 Entry_delay_time = 0; // Could get overwritten in mission read.
1556 fireball_preload(); // page in warphole bitmaps
1558 flak_level_init(); // initialize flak - bitmaps, etc
1559 ct_level_init(); // initialize ships contrails, etc
1560 awacs_level_init(); // initialize AWACS
1561 beam_level_init(); // initialize beam weapons
1562 mflash_level_init();
1564 supernova_level_init();
1566 // multiplayer dogfight hack
1569 shipfx_engine_wash_level_init();
1573 Last_view_target = NULL;
1578 // campaign wasn't ended
1579 Campaign_ended_in_mission = 0;
1582 // called when a mission is over -- does server specific stuff.
1583 void freespace_stop_mission()
1586 Game_mode &= ~GM_IN_MISSION;
1589 // called at frame interval to process networking stuff
1590 void game_do_networking()
1592 Assert( Net_player != NULL );
1593 if (!(Game_mode & GM_MULTIPLAYER)){
1597 // see if this player should be reading/writing data. Bit is set when at join
1598 // screen onward until quits back to main menu.
1599 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1603 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1606 multi_pause_do_frame();
1611 // Loads the best palette for this level, based
1612 // on nebula color and hud color. You could just call palette_load_table with
1613 // the appropriate filename, but who wants to do that.
1614 void game_load_palette()
1616 char palette_filename[1024];
1618 // We only use 3 hud colors right now
1619 // Assert( HUD_config.color >= 0 );
1620 // Assert( HUD_config.color <= 2 );
1622 Assert( Mission_palette >= 0 );
1623 Assert( Mission_palette <= 98 );
1625 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1626 strcpy( palette_filename, NOX("gamepalette-subspace") );
1628 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1631 mprintf(( "Loading palette %s\n", palette_filename ));
1633 // palette_load_table(palette_filename);
1636 void game_post_level_init()
1638 // Stuff which gets called after mission is loaded. Because player isn't created until
1639 // after mission loads, some things must get initted after the level loads
1641 model_level_post_init();
1644 hud_setup_escort_list();
1645 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1651 game_event_debug_init();
1654 training_mission_init();
1655 asteroid_create_all();
1657 game_framerate_check_init();
1661 // An estimate as to how high the count passed to game_loading_callback will go.
1662 // This is just a guess, it seems to always be about the same. The count is
1663 // proportional to the code being executed, not the time, so this works good
1664 // for a bar, assuming the code does about the same thing each time you
1665 // load a level. You can find this value by looking at the return value
1666 // of game_busy_callback(NULL), which I conveniently print out to the
1667 // debug output window with the '=== ENDING LOAD ==' stuff.
1668 //#define COUNT_ESTIMATE 3706
1669 #define COUNT_ESTIMATE 1111
1671 int Game_loading_callback_inited = 0;
1673 int Game_loading_background = -1;
1674 anim * Game_loading_ani = NULL;
1675 anim_instance *Game_loading_ani_instance;
1676 int Game_loading_frame=-1;
1678 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1687 // This gets called 10x per second and count is the number of times
1688 // game_busy() has been called since the current callback function
1690 void game_loading_callback(int count)
1692 game_do_networking();
1694 Assert( Game_loading_callback_inited==1 );
1695 Assert( Game_loading_ani != NULL );
1697 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1698 if ( framenum > Game_loading_ani->total_frames-1 ) {
1699 framenum = Game_loading_ani->total_frames-1;
1700 } else if ( framenum < 0 ) {
1705 while ( Game_loading_frame < framenum ) {
1706 Game_loading_frame++;
1707 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1711 if ( cbitmap > -1 ) {
1712 if ( Game_loading_background > -1 ) {
1713 gr_set_bitmap( Game_loading_background );
1717 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1718 gr_set_bitmap( cbitmap );
1719 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1721 bm_release(cbitmap);
1727 void game_loading_callback_init()
1729 Assert( Game_loading_callback_inited==0 );
1731 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1732 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1735 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1736 Assert( Game_loading_ani != NULL );
1737 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1738 Assert( Game_loading_ani_instance != NULL );
1739 Game_loading_frame = -1;
1741 Game_loading_callback_inited = 1;
1743 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1748 void game_loading_callback_close()
1750 Assert( Game_loading_callback_inited==1 );
1752 // Make sure bar shows all the way over.
1753 game_loading_callback(COUNT_ESTIMATE);
1755 int real_count = game_busy_callback( NULL );
1758 Game_loading_callback_inited = 0;
1761 mprintf(( "=================== ENDING LOAD ================\n" ));
1762 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1763 mprintf(( "================================================\n" ));
1765 // to remove warnings in release build
1769 free_anim_instance(Game_loading_ani_instance);
1770 Game_loading_ani_instance = NULL;
1771 anim_free(Game_loading_ani);
1772 Game_loading_ani = NULL;
1774 bm_release( Game_loading_background );
1775 common_free_interface_palette(); // restore game palette
1776 Game_loading_background = -1;
1778 gr_set_font( FONT1 );
1781 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1783 void game_maybe_update_sound_environment()
1785 // do nothing for now
1788 // Assign the sound environment for the game, based on the current mission
1790 void game_assign_sound_environment()
1793 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1794 Game_sound_env.id = SND_ENV_DRUGGED;
1795 Game_sound_env.volume = 0.800f;
1796 Game_sound_env.damping = 1.188f;
1797 Game_sound_env.decay = 6.392f;
1799 } else if (Num_asteroids > 30) {
1800 Game_sound_env.id = SND_ENV_AUDITORIUM;
1801 Game_sound_env.volume = 0.603f;
1802 Game_sound_env.damping = 0.5f;
1803 Game_sound_env.decay = 4.279f;
1806 Game_sound_env = Game_default_sound_env;
1810 Game_sound_env = Game_default_sound_env;
1811 Game_sound_env_update_timestamp = timestamp(1);
1814 // function which gets called before actually entering the mission. It is broken down into a funciton
1815 // since it will get called in one place from a single player game and from another place for
1816 // a multiplayer game
1817 void freespace_mission_load_stuff()
1819 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1820 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1821 if(!(Game_mode & GM_STANDALONE_SERVER)){
1823 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1825 game_loading_callback_init();
1827 event_music_level_init(); // preloads the first 2 seconds for each event music track
1830 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1833 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1836 ship_assign_sound_all(); // assign engine sounds to ships
1837 game_assign_sound_environment(); // assign the sound environment for this mission
1840 // call function in missionparse.cpp to fixup player/ai stuff.
1841 mission_parse_fixup_players();
1844 // Load in all the bitmaps for this level
1849 game_loading_callback_close();
1851 // the only thing we need to call on the standalone for now.
1853 // call function in missionparse.cpp to fixup player/ai stuff.
1854 mission_parse_fixup_players();
1856 // Load in all the bitmaps for this level
1862 uint load_mission_load;
1863 uint load_post_level_init;
1864 uint load_mission_stuff;
1866 // tells the server to load the mission and initialize structures
1867 int game_start_mission()
1869 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1871 load_gl_init = time(NULL);
1873 load_gl_init = time(NULL) - load_gl_init;
1875 if (Game_mode & GM_MULTIPLAYER) {
1876 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1878 // clear multiplayer stats
1879 init_multiplayer_stats();
1882 load_mission_load = time(NULL);
1883 if (mission_load()) {
1884 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1885 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1886 gameseq_post_event(GS_EVENT_MAIN_MENU);
1888 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1893 load_mission_load = time(NULL) - load_mission_load;
1895 // If this is a red alert mission in campaign mode, bash wingman status
1896 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1897 red_alert_bash_wingman_status();
1900 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1901 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1902 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1903 // game_load_palette();
1906 load_post_level_init = time(NULL);
1907 game_post_level_init();
1908 load_post_level_init = time(NULL) - load_post_level_init;
1912 void Do_model_timings_test();
1913 Do_model_timings_test();
1917 load_mission_stuff = time(NULL);
1918 freespace_mission_load_stuff();
1919 load_mission_stuff = time(NULL) - load_mission_stuff;
1924 int Interface_framerate = 0;
1927 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1928 DCF_BOOL( show_framerate, Show_framerate )
1929 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1930 DCF_BOOL( show_target_weapons, Show_target_weapons )
1931 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1932 DCF_BOOL( sound, Sound_enabled )
1933 DCF_BOOL( zbuffer, game_zbuffer )
1934 DCF_BOOL( shield_system, New_shield_system )
1935 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1936 DCF_BOOL( player_attacking, Player_attacking_enabled )
1937 DCF_BOOL( show_waypoints, Show_waypoints )
1938 DCF_BOOL( show_area_effect, Show_area_effect )
1939 DCF_BOOL( show_net_stats, Show_net_stats )
1940 DCF_BOOL( log, Log_debug_output_to_file )
1941 DCF_BOOL( training_msg_method, Training_msg_method )
1942 DCF_BOOL( show_player_pos, Show_player_pos )
1943 DCF_BOOL(i_framerate, Interface_framerate )
1945 DCF(show_mem,"Toggles showing mem usage")
1948 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1949 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1950 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1951 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1957 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1959 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1960 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1964 DCF(show_cpu,"Toggles showing cpu usage")
1967 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1968 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1969 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1970 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1976 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1978 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1979 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1986 // AL 4-8-98: always allow players to display their framerate
1989 DCF_BOOL( show_framerate, Show_framerate )
1996 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1999 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2000 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
2001 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
2002 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
2004 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" );
2005 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2007 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2010 DCF(palette_flash,"Toggles palette flash effect on/off")
2013 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2014 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2015 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2016 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2018 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2019 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2022 int Use_low_mem = 0;
2024 DCF(low_mem,"Uses low memory settings regardless of RAM")
2027 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2028 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2029 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2030 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2032 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2033 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2035 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2041 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2044 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2045 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2046 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2047 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2049 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2050 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2051 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2055 int Framerate_delay = 0;
2057 float Freespace_gamma = 1.0f;
2059 DCF(gamma,"Sets Gamma factor")
2062 dc_get_arg(ARG_FLOAT|ARG_NONE);
2063 if ( Dc_arg_type & ARG_FLOAT ) {
2064 Freespace_gamma = Dc_arg_float;
2066 dc_printf( "Gamma reset to 1.0f\n" );
2067 Freespace_gamma = 1.0f;
2069 if ( Freespace_gamma < 0.1f ) {
2070 Freespace_gamma = 0.1f;
2071 } else if ( Freespace_gamma > 5.0f ) {
2072 Freespace_gamma = 5.0f;
2074 gr_set_gamma(Freespace_gamma);
2076 char tmp_gamma_string[32];
2077 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2078 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2082 dc_printf( "Usage: gamma <float>\n" );
2083 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2084 Dc_status = 0; // don't print status if help is printed. Too messy.
2088 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2097 Game_current_mission_filename[0] = 0;
2099 // seed the random number generator
2100 Game_init_seed = time(NULL);
2101 srand( Game_init_seed );
2103 Framerate_delay = 0;
2109 extern void bm_init();
2115 // Initialize the timer before the os
2123 GetCurrentDirectory(1024, whee);
2126 getcwd (whee, 1024);
2129 strcat(whee, EXE_FNAME);
2131 //Initialize the libraries
2132 s1 = timer_get_milliseconds();
2133 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2136 e1 = timer_get_milliseconds();
2138 // time a bunch of cfopens
2140 s2 = timer_get_milliseconds();
2142 for(int idx=0; idx<10000; idx++){
2143 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2148 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2150 e2 = timer_get_milliseconds();
2153 if (Is_standalone) {
2154 std_init_standalone();
2156 os_init( Osreg_class_name, Osreg_app_name );
2157 os_set_title(Osreg_title);
2160 // initialize localization module. Make sure this is down AFTER initialzing OS.
2161 // int t1 = timer_get_milliseconds();
2164 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2166 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2169 // verify that he has a valid weapons.tbl
2170 verify_weapons_tbl();
2172 // Output version numbers to registry for auto patching purposes
2173 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2174 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2175 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2177 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2178 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2179 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2182 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2186 Asteroids_enabled = 1;
2189 /////////////////////////////
2191 /////////////////////////////
2196 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2197 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2199 if (!stricmp(ptr, NOX("no sound"))) {
2200 Cmdline_freespace_no_sound = 1;
2202 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2204 } else if (!stricmp(ptr, NOX("EAX"))) {
2209 if (!Is_standalone) {
2210 snd_init(use_a3d, use_eax);
2212 /////////////////////////////
2214 /////////////////////////////
2216 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2219 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);
2221 // fire up the UpdateLauncher executable
2223 PROCESS_INFORMATION pi;
2225 memset( &si, 0, sizeof(STARTUPINFO) );
2228 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2229 NULL, // pointer to command line string
2230 NULL, // pointer to process security attributes
2231 NULL, // pointer to thread security attributes
2232 FALSE, // handle inheritance flag
2233 CREATE_DEFAULT_ERROR_MODE, // creation flags
2234 NULL, // pointer to new environment block
2235 NULL, // pointer to current directory name
2236 &si, // pointer to STARTUPINFO
2237 &pi // pointer to PROCESS_INFORMATION
2240 // If the Launcher could not be started up, let the user know
2242 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2251 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2253 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);
2261 // check for hi res pack file
2262 int has_sparky_hi = 0;
2264 // check if sparky_hi exists -- access mode 0 means does file exist
2267 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2270 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2273 // see if we've got 32 bit in the string
2274 if(strstr(ptr, "32 bit")){
2281 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2283 // always 640 for E3
2284 gr_init(GR_640, GR_GLIDE);
2286 // regular or hi-res ?
2288 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2290 if(strstr(ptr, NOX("(1024x768)"))){
2292 gr_init(GR_1024, GR_GLIDE);
2294 gr_init(GR_640, GR_GLIDE);
2297 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2299 // always 640 for E3
2301 gr_init(GR_640, GR_DIRECT3D, depth);
2303 // regular or hi-res ?
2305 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2307 if(strstr(ptr, NOX("(1024x768)"))){
2311 gr_init(GR_1024, GR_DIRECT3D, depth);
2315 gr_init(GR_640, GR_DIRECT3D, depth);
2321 if ( Use_fullscreen_at_startup && !Is_standalone) {
2322 gr_init(GR_640, GR_DIRECTDRAW);
2324 gr_init(GR_640, GR_SOFTWARE);
2327 if ( !Is_standalone ) {
2328 gr_init(GR_640, GR_DIRECTDRAW);
2330 gr_init(GR_640, GR_SOFTWARE);
2335 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2336 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2337 gr_init(GR_1024, GR_OPENGL);
2339 gr_init(GR_640, GR_OPENGL);
2343 gr_init(GR_640, GR_SOFTWARE);
2348 extern int Gr_inited;
2349 if(trying_d3d && !Gr_inited){
2351 extern char Device_init_error[512];
2352 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2361 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2362 Freespace_gamma = (float)atof(ptr);
2363 if ( Freespace_gamma == 0.0f ) {
2364 Freespace_gamma = 1.80f;
2365 } else if ( Freespace_gamma < 0.1f ) {
2366 Freespace_gamma = 0.1f;
2367 } else if ( Freespace_gamma > 5.0f ) {
2368 Freespace_gamma = 5.0f;
2370 char tmp_gamma_string[32];
2371 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2372 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2374 gr_set_gamma(Freespace_gamma);
2376 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2379 display_title_screen();
2383 // attempt to load up master tracker registry info (login and password)
2384 Multi_tracker_id = -1;
2386 // pxo login and password
2387 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2389 nprintf(("Network","Error reading in PXO login data\n"));
2390 strcpy(Multi_tracker_login,"");
2392 strcpy(Multi_tracker_login,ptr);
2394 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2396 nprintf(("Network","Error reading PXO password\n"));
2397 strcpy(Multi_tracker_passwd,"");
2399 strcpy(Multi_tracker_passwd,ptr);
2402 // pxo squad name and password
2403 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2405 nprintf(("Network","Error reading in PXO squad name\n"));
2406 strcpy(Multi_tracker_squad_name, "");
2408 strcpy(Multi_tracker_squad_name, ptr);
2411 // If less than 48MB of RAM, use low memory model.
2414 (Freespace_total_ram < 48*1024*1024) ||
2417 mprintf(( "Using normal memory settings...\n" ));
2418 bm_set_low_mem(1); // Use every other frame of bitmaps
2420 mprintf(( "Using high memory settings...\n" ));
2421 bm_set_low_mem(0); // Use all frames of bitmaps
2424 // load non-darkening pixel defs
2425 palman_load_pixels();
2427 // hud shield icon stuff
2428 hud_shield_game_init();
2430 control_config_common_init(); // sets up localization stuff in the control config
2436 gamesnd_parse_soundstbl();
2441 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2446 player_controls_init();
2449 //if(!Is_standalone){
2457 ship_init(); // read in ships.tbl
2459 mission_campaign_init(); // load in the default campaign
2461 // navmap_init(); // init the navigation map system
2462 context_help_init();
2463 techroom_intel_init(); // parse species.tbl, load intel info
2465 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2466 init_animating_pointer();
2468 mission_brief_common_init(); // Mark all the briefing structures as empty.
2469 gr_font_init(); // loads up all fonts
2471 neb2_init(); // fullneb stuff
2475 player_tips_init(); // helpful tips
2478 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2479 pilot_load_pic_list();
2480 pilot_load_squad_pic_list();
2482 load_animating_pointer(NOX("cursor"), 0, 0);
2484 // initialize alpha colors
2485 alpha_colors_init();
2488 // Game_music_paused = 0;
2495 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2496 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2498 mprintf(("cfile_init() took %d\n", e1 - s1));
2499 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2502 char transfer_text[128];
2504 float Start_time = 0.0f;
2506 float Framerate = 0.0f;
2508 float Timing_total = 0.0f;
2509 float Timing_render2 = 0.0f;
2510 float Timing_render3 = 0.0f;
2511 float Timing_flip = 0.0f;
2512 float Timing_clear = 0.0f;
2514 MONITOR(NumPolysDrawn);
2520 void game_get_framerate()
2522 char text[128] = "";
2524 if ( frame_int == -1 ) {
2526 for (i=0; i<FRAME_FILTER; i++ ) {
2527 frametimes[i] = 0.0f;
2532 frametotal -= frametimes[frame_int];
2533 frametotal += flFrametime;
2534 frametimes[frame_int] = flFrametime;
2535 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2537 if ( frametotal != 0.0 ) {
2538 if ( Framecount >= FRAME_FILTER )
2539 Framerate = FRAME_FILTER / frametotal;
2541 Framerate = Framecount / frametotal;
2542 sprintf( text, NOX("FPS: %.1f"), Framerate );
2544 sprintf( text, NOX("FPS: ?") );
2548 if (Show_framerate) {
2549 gr_set_color_fast(&HUD_color_debug);
2550 gr_string( 570, 2, text );
2554 void game_show_framerate()
2558 cur_time = f2fl(timer_get_approx_seconds());
2559 if (cur_time - Start_time > 30.0f) {
2560 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2561 Start_time += 1000.0f;
2564 //mprintf(( "%s\n", text ));
2567 if ( Debug_dump_frames )
2571 // possibly show control checking info
2572 control_check_indicate();
2574 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2575 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2576 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2577 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2580 if ( Show_cpu == 1 ) {
2585 dy = gr_get_font_height() + 1;
2587 gr_set_color_fast(&HUD_color_debug);
2591 extern int D3D_textures_in;
2592 extern int D3D_textures_in_frame;
2593 extern int Glide_textures_in;
2594 extern int Glide_textures_in_frame;
2595 extern int Glide_explosion_vram;
2596 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2598 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2600 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2604 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2606 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2608 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2610 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2612 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2617 extern int Num_pairs; // Number of object pairs that were checked.
2618 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2621 extern int Num_pairs_checked; // What percent of object pairs were checked.
2622 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2624 Num_pairs_checked = 0;
2628 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2631 if ( Timing_total > 0.01f ) {
2632 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2634 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2636 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2638 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2640 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2650 dy = gr_get_font_height() + 1;
2652 gr_set_color_fast(&HUD_color_debug);
2655 extern int TotalRam;
2656 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2661 extern int Model_ram;
2662 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2666 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2668 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2670 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2674 extern int D3D_textures_in;
2675 extern int Glide_textures_in;
2676 extern int Glide_textures_in_frame;
2677 extern int Glide_explosion_vram;
2678 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2680 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2682 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2689 if ( Show_player_pos ) {
2693 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));
2696 MONITOR_INC(NumPolys, modelstats_num_polys);
2697 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2698 MONITOR_INC(NumVerts, modelstats_num_verts );
2700 modelstats_num_polys = 0;
2701 modelstats_num_polys_drawn = 0;
2702 modelstats_num_verts = 0;
2703 modelstats_num_sortnorms = 0;
2707 void game_show_standalone_framerate()
2709 float frame_rate=30.0f;
2710 if ( frame_int == -1 ) {
2712 for (i=0; i<FRAME_FILTER; i++ ) {
2713 frametimes[i] = 0.0f;
2718 frametotal -= frametimes[frame_int];
2719 frametotal += flFrametime;
2720 frametimes[frame_int] = flFrametime;
2721 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2723 if ( frametotal != 0.0 ) {
2724 if ( Framecount >= FRAME_FILTER ){
2725 frame_rate = FRAME_FILTER / frametotal;
2727 frame_rate = Framecount / frametotal;
2730 std_set_standalone_fps(frame_rate);
2734 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2735 void game_show_time_left()
2739 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2740 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2741 // checking how much time is left
2743 if ( Mission_end_time == -1 ){
2747 diff = f2i(Mission_end_time - Missiontime);
2748 // be sure to bash to 0. diff could be negative on frame that we quit mission
2753 hud_set_default_color();
2754 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2757 //========================================================================================
2758 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2759 //========================================================================================
2763 DCF(ai_pause,"Pauses ai")
2766 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2767 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2768 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2769 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2772 obj_init_all_ships_physics();
2775 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2776 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2779 DCF(single_step,"Single steps the game")
2782 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2783 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2784 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2785 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2787 last_single_step = 0; // Make so single step waits a frame before stepping
2790 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2791 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2794 DCF_BOOL(physics_pause, physics_paused)
2795 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2796 DCF_BOOL(ai_firing, Ai_firing_enabled )
2798 // Create some simple aliases to these commands...
2799 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2800 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2801 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2802 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2803 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2806 //========================================================================================
2807 //========================================================================================
2810 void game_training_pause_do()
2814 key = game_check_key();
2816 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2823 void game_increase_skill_level()
2826 if (Game_skill_level >= NUM_SKILL_LEVELS){
2827 Game_skill_level = 0;
2831 int Player_died_time;
2833 int View_percent = 100;
2836 DCF(view, "Sets the percent of the 3d view to render.")
2839 dc_get_arg(ARG_INT);
2840 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2841 View_percent = Dc_arg_int;
2843 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2849 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2853 dc_printf("View is set to %d%%\n", View_percent );
2858 // Set the clip region for the 3d rendering window
2859 void game_set_view_clip()
2861 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2862 // Set the clip region for the letterbox "dead view"
2863 int yborder = gr_screen.max_h/4;
2865 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2866 // J.S. I've changed my ways!! See the new "no constants" code!!!
2867 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2869 // Set the clip region for normal view
2870 if ( View_percent >= 100 ) {
2873 int xborder, yborder;
2875 if ( View_percent < 5 ) {
2879 float fp = i2fl(View_percent)/100.0f;
2880 int fi = fl2i(fl_sqrt(fp)*100.0f);
2881 if ( fi > 100 ) fi=100;
2883 xborder = ( gr_screen.max_w*(100-fi) )/200;
2884 yborder = ( gr_screen.max_h*(100-fi) )/200;
2886 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2892 void show_debug_stuff()
2895 int laser_count = 0, missile_count = 0;
2897 for (i=0; i<MAX_OBJECTS; i++) {
2898 if (Objects[i].type == OBJ_WEAPON){
2899 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2901 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2907 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2910 extern int Tool_enabled;
2915 int tst_bitmap = -1;
2917 float tst_offset, tst_offset_total;
2920 void game_tst_frame_pre()
2928 g3_rotate_vertex(&v, &tst_pos);
2929 g3_project_vertex(&v);
2932 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2936 // big ship? always tst
2938 // within 3000 meters
2939 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2943 // within 300 meters
2944 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2951 void game_tst_frame()
2961 tst_time = time(NULL);
2963 // load the tst bitmap
2964 switch((int)frand_range(0.0f, 3.0)){
2966 tst_bitmap = bm_load("ig_jim");
2968 mprintf(("TST 0\n"));
2972 tst_bitmap = bm_load("ig_kan");
2974 mprintf(("TST 1\n"));
2978 tst_bitmap = bm_load("ig_jim");
2980 mprintf(("TST 2\n"));
2984 tst_bitmap = bm_load("ig_kan");
2986 mprintf(("TST 3\n"));
2995 // get the tst bitmap dimensions
2997 bm_get_info(tst_bitmap, &w, &h);
3000 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
3002 snd_play(&Snds[SND_VASUDAN_BUP]);
3004 // tst x and direction
3008 tst_offset_total = (float)w;
3009 tst_offset = (float)w;
3011 tst_x = (float)gr_screen.max_w;
3012 tst_offset_total = (float)-w;
3013 tst_offset = (float)w;
3021 float diff = (tst_offset_total / 0.5f) * flFrametime;
3027 tst_offset -= fl_abs(diff);
3028 } else if(tst_mode == 2){
3031 tst_offset -= fl_abs(diff);
3035 gr_set_bitmap(tst_bitmap);
3036 gr_bitmap((int)tst_x, (int)tst_y);
3039 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3043 // if we passed the switch point
3044 if(tst_offset <= 0.0f){
3049 tst_stamp = timestamp(1000);
3050 tst_offset = fl_abs(tst_offset_total);
3061 void game_tst_mark(object *objp, ship *shipp)
3070 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3073 sip = &Ship_info[shipp->ship_info_index];
3080 tst_pos = objp->pos;
3081 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3087 extern void render_shields();
3089 void player_repair_frame(float frametime)
3091 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3093 for(idx=0;idx<MAX_PLAYERS;idx++){
3096 np = &Net_players[idx];
3098 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)){
3100 // don't rearm/repair if the player is dead or dying/departing
3101 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3102 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3107 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3108 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3114 #define NUM_FRAMES_TEST 300
3115 #define NUM_MIXED_SOUNDS 16
3116 void do_timing_test(float flFrametime)
3118 static int framecount = 0;
3119 static int test_running = 0;
3120 static float test_time = 0.0f;
3122 static int snds[NUM_MIXED_SOUNDS];
3125 if ( test_running ) {
3127 test_time += flFrametime;
3128 if ( framecount >= NUM_FRAMES_TEST ) {
3130 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3131 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3136 if ( Test_begin == 1 ) {
3142 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3145 // start looping digital sounds
3146 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3147 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3154 DCF(dcf_fov, "Change the field of view")
3157 dc_get_arg(ARG_FLOAT|ARG_NONE);
3158 if ( Dc_arg_type & ARG_NONE ) {
3159 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3160 dc_printf( "Zoom factor reset\n" );
3162 if ( Dc_arg_type & ARG_FLOAT ) {
3163 if (Dc_arg_float < 0.25f) {
3164 Viewer_zoom = 0.25f;
3165 dc_printf("Zoom factor pinned at 0.25.\n");
3166 } else if (Dc_arg_float > 1.25f) {
3167 Viewer_zoom = 1.25f;
3168 dc_printf("Zoom factor pinned at 1.25.\n");
3170 Viewer_zoom = Dc_arg_float;
3176 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3179 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3183 DCF(framerate_cap, "Sets the framerate cap")
3186 dc_get_arg(ARG_INT);
3187 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3188 Framerate_cap = Dc_arg_int;
3190 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3196 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3197 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3198 dc_printf("[n] must be from 1 to 120.\n");
3202 if ( Framerate_cap )
3203 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3205 dc_printf("There is no framerate cap currently active.\n");
3209 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3210 int Show_viewing_from_self = 0;
3212 void say_view_target()
3214 object *view_target;
3216 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3217 view_target = &Objects[Player_ai->target_objnum];
3219 view_target = Player_obj;
3221 if (Game_mode & GM_DEAD) {
3222 if (Player_ai->target_objnum != -1)
3223 view_target = &Objects[Player_ai->target_objnum];
3226 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3227 if (view_target != Player_obj){
3229 char *view_target_name = NULL;
3230 switch(Objects[Player_ai->target_objnum].type) {
3232 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3235 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3236 Viewer_mode &= ~VM_OTHER_SHIP;
3238 case OBJ_JUMP_NODE: {
3239 char jump_node_name[128];
3240 strcpy(jump_node_name, XSTR( "jump node", 184));
3241 view_target_name = jump_node_name;
3242 Viewer_mode &= ~VM_OTHER_SHIP;
3251 if ( view_target_name ) {
3252 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3253 Show_viewing_from_self = 1;
3256 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3257 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3258 Show_viewing_from_self = 1;
3260 if (Show_viewing_from_self)
3261 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3266 Last_view_target = view_target;
3270 float Game_hit_x = 0.0f;
3271 float Game_hit_y = 0.0f;
3273 // Reset at the beginning of each frame
3274 void game_whack_reset()
3280 // Apply a 2d whack to the player
3281 void game_whack_apply( float x, float y )
3283 // Do some force feedback
3284 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3290 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3293 // call to apply a "shudder"
3294 void game_shudder_apply(int time, float intensity)
3296 Game_shudder_time = timestamp(time);
3297 Game_shudder_total = time;
3298 Game_shudder_intensity = intensity;
3301 #define FF_SCALE 10000
3302 void apply_hud_shake(matrix *eye_orient)
3304 if (Viewer_obj == Player_obj) {
3305 physics_info *pi = &Player_obj->phys_info;
3313 // Make eye shake due to afterburner
3314 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3317 dtime = timestamp_until(pi->afterburner_decay);
3321 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3322 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3325 // Make eye shake due to engine wash
3327 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3330 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3331 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3333 // get the intensity
3334 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3338 vm_vec_rand_vec_quick(&rand_vec);
3341 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3345 // make hud shake due to shuddering
3346 if(Game_shudder_time != -1){
3347 // if the timestamp has elapsed
3348 if(timestamp_elapsed(Game_shudder_time)){
3349 Game_shudder_time = -1;
3351 // otherwise apply some shudder
3355 dtime = timestamp_until(Game_shudder_time);
3359 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));
3360 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));
3365 vm_angles_2_matrix(&tm, &tangles);
3366 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3367 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3368 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3369 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3374 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3376 // Player's velocity just before he blew up. Used to keep camera target moving.
3377 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3379 // Set eye_pos and eye_orient based on view mode.
3380 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3384 static int last_Viewer_mode = 0;
3385 static int last_Game_mode = 0;
3386 static int last_Viewer_objnum = -1;
3388 // This code is supposed to detect camera "cuts"... like going between
3391 // determine if we need to regenerate the nebula
3392 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3393 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3394 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3395 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3396 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3397 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3398 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3399 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3400 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3403 // regenerate the nebula
3407 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3408 //mprintf(( "************** Camera cut! ************\n" ));
3409 last_Viewer_mode = Viewer_mode;
3410 last_Game_mode = Game_mode;
3412 // Camera moved. Tell stars & debris to not do blurring.
3418 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3419 player_display_packlock_view();
3422 game_set_view_clip();
3424 if (Game_mode & GM_DEAD) {
3425 vector vec_to_deader, view_pos;
3428 Viewer_mode |= VM_DEAD_VIEW;
3430 if (Player_ai->target_objnum != -1) {
3431 int view_from_player = 1;
3433 if (Viewer_mode & VM_OTHER_SHIP) {
3434 // View from target.
3435 Viewer_obj = &Objects[Player_ai->target_objnum];
3437 last_Viewer_objnum = Player_ai->target_objnum;
3439 if ( Viewer_obj->type == OBJ_SHIP ) {
3440 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3441 view_from_player = 0;
3444 last_Viewer_objnum = -1;
3447 if ( view_from_player ) {
3448 // View target from player ship.
3450 *eye_pos = Player_obj->pos;
3451 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3452 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3455 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3457 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3458 dist += flFrametime * 16.0f;
3460 vm_vec_scale(&vec_to_deader, -dist);
3461 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3463 view_pos = Player_obj->pos;
3465 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3466 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3467 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3468 Dead_player_last_vel = Player_obj->phys_info.vel;
3469 //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));
3470 } else if (Player_ai->target_objnum != -1) {
3471 view_pos = Objects[Player_ai->target_objnum].pos;
3473 // Make camera follow explosion, but gradually slow down.
3474 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3475 view_pos = Player_obj->pos;
3476 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3477 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3480 *eye_pos = Dead_camera_pos;
3482 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3484 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3489 // if supernova shockwave
3490 if(supernova_camera_cut()){
3494 // call it dead view
3495 Viewer_mode |= VM_DEAD_VIEW;
3497 // set eye pos and orient
3498 supernova_set_view(eye_pos, eye_orient);
3500 // If already blown up, these other modes can override.
3501 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3502 Viewer_mode &= ~VM_DEAD_VIEW;
3504 Viewer_obj = Player_obj;
3506 if (Viewer_mode & VM_OTHER_SHIP) {
3507 if (Player_ai->target_objnum != -1){
3508 Viewer_obj = &Objects[Player_ai->target_objnum];
3509 last_Viewer_objnum = Player_ai->target_objnum;
3511 Viewer_mode &= ~VM_OTHER_SHIP;
3512 last_Viewer_objnum = -1;
3515 last_Viewer_objnum = -1;
3518 if (Viewer_mode & VM_EXTERNAL) {
3521 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3522 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3524 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3526 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3527 vm_vec_normalize(&eye_dir);
3528 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3531 // Modify the orientation based on head orientation.
3532 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3534 } else if ( Viewer_mode & VM_CHASE ) {
3537 if ( Viewer_obj->phys_info.speed < 0.1 )
3538 move_dir = Viewer_obj->orient.v.fvec;
3540 move_dir = Viewer_obj->phys_info.vel;
3541 vm_vec_normalize(&move_dir);
3544 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3545 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3546 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3547 vm_vec_normalize(&eye_dir);
3549 // JAS: I added the following code because if you slew up using
3550 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3551 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3552 // call because the up and the forward vector are the same. I fixed
3553 // it by adding in a fraction of the right vector all the time to the
3555 vector tmp_up = Viewer_obj->orient.v.uvec;
3556 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3558 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3561 // Modify the orientation based on head orientation.
3562 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3563 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3564 *eye_pos = Camera_pos;
3566 ship * shipp = &Ships[Player_obj->instance];
3568 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3569 vm_vec_normalize(&eye_dir);
3570 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3573 // get an eye position based upon the correct type of object
3574 switch(Viewer_obj->type){
3576 // make a call to get the eye point for the player object
3577 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3580 // make a call to get the eye point for the player object
3581 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3587 #ifdef JOHNS_DEBUG_CODE
3588 john_debug_stuff(&eye_pos, &eye_orient);
3594 apply_hud_shake(eye_orient);
3596 // setup neb2 rendering
3597 neb2_render_setup(eye_pos, eye_orient);
3601 extern void ai_debug_render_stuff();
3604 int Game_subspace_effect = 0;
3605 DCF_BOOL( subspace, Game_subspace_effect );
3607 // Does everything needed to render a frame
3608 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3612 g3_start_frame(game_zbuffer);
3613 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3615 // maybe offset the HUD (jitter stuff)
3616 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3617 HUD_set_offsets(Viewer_obj, !dont_offset);
3619 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3620 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3621 // must be done before ships are rendered
3622 if ( MULTIPLAYER_CLIENT ) {
3623 shield_point_multi_setup();
3626 if ( Game_subspace_effect ) {
3627 stars_draw(0,0,0,1);
3629 stars_draw(1,1,1,0);
3632 obj_render_all(obj_render);
3633 beam_render_all(); // render all beam weapons
3634 particle_render_all(); // render particles after everything else.
3635 trail_render_all(); // render missilie trails after everything else.
3636 mflash_render_all(); // render all muzzle flashes
3638 // Why do we not show the shield effect in these modes? Seems ok.
3639 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3643 // render nebula lightning
3646 // render local player nebula
3647 neb2_render_player();
3650 ai_debug_render_stuff();
3653 #ifndef RELEASE_REAL
3654 // game_framerate_check();
3658 extern void snd_spew_debug_info();
3659 snd_spew_debug_info();
3662 //================ END OF 3D RENDERING STUFF ====================
3666 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3667 hud_maybe_clear_head_area();
3668 anim_render_all(0, flFrametime);
3671 extern int Multi_display_netinfo;
3672 if(Multi_display_netinfo){
3673 extern void multi_display_netinfo();
3674 multi_display_netinfo();
3677 game_tst_frame_pre();
3680 do_timing_test(flFrametime);
3684 extern int OO_update_index;
3685 multi_rate_display(OO_update_index, 375, 0);
3690 extern void oo_display();
3697 //#define JOHNS_DEBUG_CODE 1
3699 #ifdef JOHNS_DEBUG_CODE
3700 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3702 //if ( keyd_pressed[KEY_LSHIFT] )
3704 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3706 model_subsystem *turret = tsys->system_info;
3708 if (turret->type == SUBSYSTEM_TURRET ) {
3709 vector v.fvec, v.uvec;
3710 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3712 ship_model_start(tobj);
3714 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3715 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3716 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3718 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3720 ship_model_stop(tobj);
3730 // following function for dumping frames for purposes of building trailers.
3733 // function to toggle state of dumping every frame into PCX when playing the game
3734 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3738 if ( Debug_dump_frames == 0 ) {
3740 Debug_dump_frames = 15;
3741 Debug_dump_trigger = 0;
3742 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3743 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3746 Debug_dump_frames = 0;
3747 Debug_dump_trigger = 0;
3748 gr_dump_frame_stop();
3749 dc_printf( "Frame dumping is now OFF\n" );
3755 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3759 if ( Debug_dump_frames == 0 ) {
3761 Debug_dump_frames = 15;
3762 Debug_dump_trigger = 1;
3763 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3764 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3767 Debug_dump_frames = 0;
3768 Debug_dump_trigger = 0;
3769 gr_dump_frame_stop();
3770 dc_printf( "Frame dumping is now OFF\n" );
3776 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3780 if ( Debug_dump_frames == 0 ) {
3782 Debug_dump_frames = 30;
3783 Debug_dump_trigger = 0;
3784 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3785 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3788 Debug_dump_frames = 0;
3789 Debug_dump_trigger = 0;
3790 gr_dump_frame_stop();
3791 dc_printf( "Frame dumping is now OFF\n" );
3797 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3801 if ( Debug_dump_frames == 0 ) {
3803 Debug_dump_frames = 30;
3804 Debug_dump_trigger = 1;
3805 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3806 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3809 Debug_dump_frames = 0;
3810 Debug_dump_trigger = 0;
3811 gr_dump_frame_stop();
3812 dc_printf( "Triggered frame dumping is now OFF\n" );
3818 void game_maybe_dump_frame()
3820 if ( !Debug_dump_frames ){
3824 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3831 Debug_dump_frame_num++;
3837 extern int Player_dead_state;
3839 // Flip the page and time how long it took.
3840 void game_flip_page_and_time_it()
3844 t1 = timer_get_fixed_seconds();
3846 t2 = timer_get_fixed_seconds();
3848 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3849 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3852 void game_simulation_frame()
3854 // blow ships up in multiplayer dogfight
3855 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){
3856 // blow up all non-player ships
3857 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3860 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3862 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)){
3863 moveup = GET_NEXT(moveup);
3866 shipp = &Ships[Objects[moveup->objnum].instance];
3867 sip = &Ship_info[shipp->ship_info_index];
3869 // only blow up small ships
3870 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3871 // function to simply explode a ship where it is currently at
3872 ship_self_destruct( &Objects[moveup->objnum] );
3875 moveup = GET_NEXT(moveup);
3881 // process AWACS stuff - do this first thing
3884 // single player, set Player hits_this_frame to 0
3885 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3886 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3887 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3891 supernova_process();
3892 if(supernova_active() >= 5){
3896 // fire targeting lasers now so that
3897 // 1 - created this frame
3898 // 2 - collide this frame
3899 // 3 - render this frame
3900 // 4 - ignored and deleted next frame
3901 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3903 ship_process_targeting_lasers();
3905 // do this here so that it works for multiplayer
3907 // get viewer direction
3908 int viewer_direction = PHYSICS_VIEWER_REAR;
3910 if(Viewer_mode == 0){
3911 viewer_direction = PHYSICS_VIEWER_FRONT;
3913 if(Viewer_mode & VM_PADLOCK_UP){
3914 viewer_direction = PHYSICS_VIEWER_UP;
3916 else if(Viewer_mode & VM_PADLOCK_REAR){
3917 viewer_direction = PHYSICS_VIEWER_REAR;
3919 else if(Viewer_mode & VM_PADLOCK_LEFT){
3920 viewer_direction = PHYSICS_VIEWER_LEFT;
3922 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3923 viewer_direction = PHYSICS_VIEWER_RIGHT;
3926 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3928 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3931 #define VM_PADLOCK_UP (1 << 7)
3932 #define VM_PADLOCK_REAR (1 << 8)
3933 #define VM_PADLOCK_LEFT (1 << 9)
3934 #define VM_PADLOCK_RIGHT (1 << 10)
3936 // evaluate mission departures and arrivals before we process all objects.
3937 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3939 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3940 // ships/wing packets.
3941 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3942 mission_parse_eval_stuff();
3945 // if we're an observer, move ourselves seperately from the standard physics
3946 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3947 obj_observer_move(flFrametime);
3950 // move all the objects now
3951 obj_move_all(flFrametime);
3953 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3954 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3955 // ship_check_cargo_all();
3956 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3957 mission_eval_goals();
3961 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3962 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3963 training_check_objectives();
3966 // do all interpolation now
3967 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3968 // client side processing of warping in effect stages
3969 multi_do_client_warp(flFrametime);
3971 // client side movement of an observer
3972 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3973 obj_observer_move(flFrametime);
3976 // move all objects - does interpolation now as well
3977 obj_move_all(flFrametime);
3980 // only process the message queue when the player is "in" the game
3981 if ( !Pre_player_entry ){
3982 message_queue_process(); // process any messages send to the player
3985 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3986 message_maybe_distort(); // maybe distort incoming message if comms damaged
3987 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3988 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3989 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3992 if(!(Game_mode & GM_STANDALONE_SERVER)){
3993 // process some stuff every frame (before frame is rendered)
3994 emp_process_local();
3996 hud_update_frame(); // update hud systems
3998 if (!physics_paused) {
3999 // Move particle system
4000 particle_move_all(flFrametime);
4002 // Move missile trails
4003 trail_move_all(flFrametime);
4005 // process muzzle flashes
4006 mflash_process_all();
4008 // Flash the gun flashes
4009 shipfx_flash_do_frame(flFrametime);
4011 shockwave_move_all(flFrametime); // update all the shockwaves
4014 // subspace missile strikes
4017 obj_snd_do_frame(); // update the object-linked persistant sounds
4018 game_maybe_update_sound_environment();
4019 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4021 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4023 if ( Game_subspace_effect ) {
4024 game_start_subspace_ambient_sound();
4030 // Maybe render and process the dead-popup
4031 void game_maybe_do_dead_popup(float frametime)
4033 if ( popupdead_is_active() ) {
4035 int choice = popupdead_do_frame(frametime);
4037 if ( Game_mode & GM_NORMAL ) {
4041 if(game_do_cd_mission_check(Game_current_mission_filename)){
4042 gameseq_post_event(GS_EVENT_ENTER_GAME);
4044 gameseq_post_event(GS_EVENT_MAIN_MENU);
4049 gameseq_post_event(GS_EVENT_END_GAME);
4054 if(game_do_cd_mission_check(Game_current_mission_filename)){
4055 gameseq_post_event(GS_EVENT_START_GAME);
4057 gameseq_post_event(GS_EVENT_MAIN_MENU);
4061 // this should only happen during a red alert mission
4064 Assert(The_mission.red_alert);
4065 if(!The_mission.red_alert){
4067 if(game_do_cd_mission_check(Game_current_mission_filename)){
4068 gameseq_post_event(GS_EVENT_START_GAME);
4070 gameseq_post_event(GS_EVENT_MAIN_MENU);
4075 // choose the previous mission
4076 mission_campaign_previous_mission();
4078 if(game_do_cd_mission_check(Game_current_mission_filename)){
4079 gameseq_post_event(GS_EVENT_START_GAME);
4081 gameseq_post_event(GS_EVENT_MAIN_MENU);
4092 case POPUPDEAD_DO_MAIN_HALL:
4093 multi_quit_game(PROMPT_NONE,-1);
4096 case POPUPDEAD_DO_RESPAWN:
4097 multi_respawn_normal();
4098 event_music_player_respawn();
4101 case POPUPDEAD_DO_OBSERVER:
4102 multi_respawn_observer();
4103 event_music_player_respawn_as_observer();
4112 if ( leave_popup ) {
4118 // returns true if player is actually in a game_play stats
4119 int game_actually_playing()
4123 state = gameseq_get_state();
4124 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4130 // Draw the 2D HUD gauges
4131 void game_render_hud_2d()
4133 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4137 HUD_render_2d(flFrametime);
4141 // Draw the 3D-dependant HUD gauges
4142 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4144 g3_start_frame(0); // 0 = turn zbuffering off
4145 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4147 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4148 HUD_render_3d(flFrametime);
4152 game_sunspot_process(flFrametime);
4154 // Diminish the palette effect
4155 game_flash_diminish(flFrametime);
4163 int actually_playing;
4164 fix total_time1, total_time2;
4165 fix render2_time1=0, render2_time2=0;
4166 fix render3_time1=0, render3_time2=0;
4167 fix flip_time1=0, flip_time2=0;
4168 fix clear_time1=0, clear_time2=0;
4174 if (Framerate_delay) {
4175 int start_time = timer_get_milliseconds();
4176 while (timer_get_milliseconds() < start_time + Framerate_delay)
4182 demo_do_frame_start();
4184 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4189 // start timing frame
4190 timing_frame_start();
4192 total_time1 = timer_get_fixed_seconds();
4194 // var to hold which state we are in
4195 actually_playing = game_actually_playing();
4197 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4198 if (!(Game_mode & GM_STANDALONE_SERVER)){
4199 Assert( OBJ_INDEX(Player_obj) >= 0 );
4203 if (Missiontime > Entry_delay_time){
4204 Pre_player_entry = 0;
4206 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4209 // Note: These are done even before the player enters, else buffers can overflow.
4210 if (! (Game_mode & GM_STANDALONE_SERVER)){
4214 shield_frame_init();
4216 if ( Player->control_mode != PCM_NORMAL )
4219 if ( !Pre_player_entry && actually_playing ) {
4220 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4222 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4223 game_process_keys();
4225 // don't read flying controls if we're playing a demo back
4226 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4227 read_player_controls( Player_obj, flFrametime);
4231 // if we're not the master, we may have to send the server-critical ship status button_info bits
4232 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4233 multi_maybe_send_ship_status();
4238 // Reset the whack stuff
4241 // These two lines must be outside of Pre_player_entry code,
4242 // otherwise too many lights are added.
4245 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4249 game_simulation_frame();
4251 // if not actually in a game play state, then return. This condition could only be true in
4252 // a multiplayer game.
4253 if ( !actually_playing ) {
4254 Assert( Game_mode & GM_MULTIPLAYER );
4258 if (!Pre_player_entry) {
4259 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4260 clear_time1 = timer_get_fixed_seconds();
4261 // clear the screen to black
4263 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4267 clear_time2 = timer_get_fixed_seconds();
4268 render3_time1 = timer_get_fixed_seconds();
4269 game_render_frame_setup(&eye_pos, &eye_orient);
4270 game_render_frame( &eye_pos, &eye_orient );
4272 // save the eye position and orientation
4273 if ( Game_mode & GM_MULTIPLAYER ) {
4274 Net_player->s_info.eye_pos = eye_pos;
4275 Net_player->s_info.eye_orient = eye_orient;
4278 hud_show_target_model();
4280 // check to see if we should display the death died popup
4281 if(Game_mode & GM_DEAD_BLEW_UP){
4282 if(Game_mode & GM_MULTIPLAYER){
4283 // catch the situation where we're supposed to be warping out on this transition
4284 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4285 gameseq_post_event(GS_EVENT_DEBRIEF);
4286 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4287 Player_died_popup_wait = -1;
4291 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4292 Player_died_popup_wait = -1;
4298 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4299 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4300 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4301 if(!popupdead_is_active()){
4305 Player_multi_died_check = -1;
4309 render3_time2 = timer_get_fixed_seconds();
4310 render2_time1 = timer_get_fixed_seconds();
4313 game_get_framerate();
4314 game_show_framerate();
4316 game_show_time_left();
4318 // Draw the 2D HUD gauges
4319 if(supernova_active() < 3){
4320 game_render_hud_2d();
4323 game_set_view_clip();
4325 // Draw 3D HUD gauges
4326 game_render_hud_3d(&eye_pos, &eye_orient);
4330 render2_time2 = timer_get_fixed_seconds();
4332 // maybe render and process the dead popup
4333 game_maybe_do_dead_popup(flFrametime);
4335 // start timing frame
4336 timing_frame_stop();
4337 // timing_display(30, 10);
4339 // If a regular popup is active, don't flip (popup code flips)
4340 if( !popup_running_state() ){
4341 flip_time1 = timer_get_fixed_seconds();
4342 game_flip_page_and_time_it();
4343 flip_time2 = timer_get_fixed_seconds();
4347 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4350 game_show_standalone_framerate();
4354 game_do_training_checks();
4357 // process lightning (nebula only)
4360 total_time2 = timer_get_fixed_seconds();
4362 // Got some timing numbers
4363 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4364 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4365 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4366 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4367 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4370 demo_do_frame_end();
4372 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4378 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4379 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4380 // died. This resulted in screwed up death sequences.
4382 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4383 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4384 static int timer_paused=0;
4385 #if defined(TIMER_TEST) && !defined(NDEBUG)
4386 static int stop_count,start_count;
4387 static int time_stopped,time_started;
4389 int saved_timestamp_ticker = -1;
4391 void game_reset_time()
4393 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4397 // Last_time = timer_get_fixed_seconds();
4403 void game_stop_time()
4405 if (timer_paused==0) {
4407 time = timer_get_fixed_seconds();
4408 // Save how much time progressed so far in the frame so we can
4409 // use it when we unpause.
4410 Last_delta_time = time - Last_time;
4412 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4413 if (Last_delta_time < 0) {
4414 #if defined(TIMER_TEST) && !defined(NDEBUG)
4415 Int3(); //get Matt!!!!
4417 Last_delta_time = 0;
4419 #if defined(TIMER_TEST) && !defined(NDEBUG)
4420 time_stopped = time;
4423 // Stop the timer_tick stuff...
4424 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4425 saved_timestamp_ticker = timestamp_ticker;
4429 #if defined(TIMER_TEST) && !defined(NDEBUG)
4434 void game_start_time()
4437 Assert(timer_paused >= 0);
4438 if (timer_paused==0) {
4440 time = timer_get_fixed_seconds();
4441 #if defined(TIMER_TEST) && !defined(NDEBUG)
4443 Int3(); //get Matt!!!!
4446 // Take current time, and set it backwards to account for time
4447 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4448 // will be correct when it goes to calculate the frametime next
4450 Last_time = time - Last_delta_time;
4451 #if defined(TIMER_TEST) && !defined(NDEBUG)
4452 time_started = time;
4455 // Restore the timer_tick stuff...
4456 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4457 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4458 timestamp_ticker = saved_timestamp_ticker;
4459 saved_timestamp_ticker = -1;
4462 #if defined(TIMER_TEST) && !defined(NDEBUG)
4468 void game_set_frametime(int state)
4471 float frame_cap_diff;
4473 thistime = timer_get_fixed_seconds();
4475 if ( Last_time == 0 )
4476 Frametime = F1_0 / 30;
4478 Frametime = thistime - Last_time;
4480 // Frametime = F1_0 / 30;
4482 fix debug_frametime = Frametime; // Just used to display frametime.
4484 // If player hasn't entered mission yet, make frame take 1/4 second.
4485 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4488 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4490 fix frame_speed = F1_0 / Debug_dump_frames;
4492 if (Frametime > frame_speed ){
4493 nprintf(("warning","slow frame: %x\n",Frametime));
4496 thistime = timer_get_fixed_seconds();
4497 Frametime = thistime - Last_time;
4498 } while (Frametime < frame_speed );
4500 Frametime = frame_speed;
4504 Assert( Framerate_cap > 0 );
4506 // Cap the framerate so it doesn't get too high.
4510 cap = F1_0/Framerate_cap;
4511 if (Frametime < cap) {
4512 thistime = cap - Frametime;
4513 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4514 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4516 thistime = timer_get_fixed_seconds();
4520 if((Game_mode & GM_STANDALONE_SERVER) &&
4521 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4523 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4524 Sleep((DWORD)(frame_cap_diff*1000));
4526 thistime += fl2f((frame_cap_diff));
4528 Frametime = thistime - Last_time;
4531 // If framerate is too low, cap it.
4532 if (Frametime > MAX_FRAMETIME) {
4534 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4536 // to remove warnings in release build
4537 debug_frametime = fl2f(flFrametime);
4539 Frametime = MAX_FRAMETIME;
4542 Frametime = fixmul(Frametime, Game_time_compression);
4544 Last_time = thistime;
4545 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4547 flFrametime = f2fl(Frametime);
4548 //if(!(Game_mode & GM_PLAYING_DEMO)){
4549 timestamp_inc(flFrametime);
4551 /* if ((Framecount > 0) && (Framecount < 10)) {
4552 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4557 // This is called from game_do_frame(), and from navmap_do_frame()
4558 void game_update_missiontime()
4560 // TODO JAS: Put in if and move this into game_set_frametime,
4561 // fix navmap to call game_stop/start_time
4562 //if ( !timer_paused )
4563 Missiontime += Frametime;
4566 void game_do_frame()
4568 game_set_frametime(GS_STATE_GAME_PLAY);
4569 game_update_missiontime();
4571 if (Game_mode & GM_STANDALONE_SERVER) {
4572 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4575 if ( game_single_step && (last_single_step == game_single_step) ) {
4576 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4577 while( key_checkch() == 0 )
4579 os_set_title( XSTR( "FreeSpace", 171) );
4580 Last_time = timer_get_fixed_seconds();
4583 last_single_step = game_single_step;
4585 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4586 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4590 Keep_mouse_centered = 0;
4591 monitor_update(); // Update monitor variables
4594 void multi_maybe_do_frame()
4596 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4601 int Joymouse_button_status = 0;
4603 // Flush all input devices
4611 Joymouse_button_status = 0;
4613 //mprintf(("Game flush!\n" ));
4616 // function for multiplayer only which calls game_do_state_common() when running the
4618 void game_do_dc_networking()
4620 Assert( Game_mode & GM_MULTIPLAYER );
4622 game_do_state_common( gameseq_get_state() );
4625 // Call this whenever in a loop, or when you need to check for a keystroke.
4626 int game_check_key()
4632 // convert keypad enter to normal enter
4633 if ((k & KEY_MASK) == KEY_PADENTER)
4634 k = (k & ~KEY_MASK) | KEY_ENTER;
4641 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4642 static int Demo_show_trailer_timestamp = 0;
4644 void demo_reset_trailer_timer()
4646 Demo_show_trailer_timestamp = timer_get_milliseconds();
4649 void demo_maybe_show_trailer(int k)
4652 // if key pressed, reset demo trailer timer
4654 demo_reset_trailer_timer();
4658 // if mouse moved, reset demo trailer timer
4661 mouse_get_delta(&dx, &dy);
4662 if ( (dx > 0) || (dy > 0) ) {
4663 demo_reset_trailer_timer();
4667 // if joystick has moved, reset demo trailer timer
4670 joy_get_delta(&dx, &dy);
4671 if ( (dx > 0) || (dy > 0) ) {
4672 demo_reset_trailer_timer();
4676 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4677 // the low-level code. Ugly, I know... but was the simplest and most
4680 // if 30 seconds since last demo trailer time reset, launch movie
4681 if ( os_foreground() ) {
4682 int now = timer_get_milliseconds();
4683 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4684 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4686 movie_play( NOX("fstrailer2.mve") );
4687 demo_reset_trailer_timer();
4695 // same as game_check_key(), except this is used while actually in the game. Since there
4696 // generally are differences between game control keys and general UI keys, makes sense to
4697 // have seperate functions for each case. If you are not checking a game control while in a
4698 // mission, you should probably be using game_check_key() instead.
4703 if (!os_foreground()) {
4708 // If we're in a single player game, pause it.
4709 if (!(Game_mode & GM_MULTIPLAYER)){
4710 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4711 game_process_pause_key();
4719 demo_maybe_show_trailer(k);
4722 // Move the mouse cursor with the joystick.
4723 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4724 // Move the mouse cursor with the joystick
4728 joy_get_pos( &jx, &jy, &jz, &jr );
4730 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4731 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4734 mouse_get_real_pos( &mx, &my );
4735 mouse_set_pos( mx+dx, my+dy );
4740 m = mouse_down(MOUSE_LEFT_BUTTON);
4742 if ( j != Joymouse_button_status ) {
4743 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4744 Joymouse_button_status = j;
4746 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4747 } else if ( (!j) && (m) ) {
4748 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4753 // if we should be ignoring keys because of some multiplayer situations
4754 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4758 // If a popup is running, don't process all the Fn keys
4759 if( popup_active() ) {
4763 state = gameseq_get_state();
4765 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4768 case KEY_DEBUGGED + KEY_BACKSP:
4773 launch_context_help();
4778 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4780 // don't allow f2 while warping out in multiplayer
4781 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4786 case GS_STATE_INITIAL_PLAYER_SELECT:
4787 case GS_STATE_OPTIONS_MENU:
4788 case GS_STATE_HUD_CONFIG:
4789 case GS_STATE_CONTROL_CONFIG:
4790 case GS_STATE_DEATH_DIED:
4791 case GS_STATE_DEATH_BLEW_UP:
4792 case GS_STATE_VIEW_MEDALS:
4796 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4803 // hotkey selection screen -- only valid from briefing and beyond.
4806 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) ) {
4807 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4813 case KEY_DEBUGGED + KEY_F3:
4814 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4817 case KEY_DEBUGGED + KEY_F4:
4818 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4822 if(Game_mode & GM_MULTIPLAYER){
4823 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4824 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4828 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4829 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4835 case KEY_ESC | KEY_SHIFTED:
4836 // make sure to quit properly out of multiplayer
4837 if(Game_mode & GM_MULTIPLAYER){
4838 multi_quit_game(PROMPT_NONE);
4841 gameseq_post_event( GS_EVENT_QUIT_GAME );
4846 case KEY_DEBUGGED + KEY_P:
4849 case KEY_PRINT_SCRN:
4851 static int counter = 0;
4856 sprintf( tmp_name, NOX("screen%02d"), counter );
4858 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4859 gr_print_screen(tmp_name);
4867 case KEY_SHIFTED | KEY_ENTER: {
4869 #if !defined(NDEBUG)
4871 if ( Game_mode & GM_NORMAL ){
4875 // if we're in multiplayer mode, do some special networking
4876 if(Game_mode & GM_MULTIPLAYER){
4877 debug_console(game_do_dc_networking);
4884 if ( Game_mode & GM_NORMAL )
4898 gameseq_post_event(GS_EVENT_QUIT_GAME);
4901 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4904 void camera_set_position( vector *pos )
4909 void camera_set_orient( matrix *orient )
4911 Camera_orient = *orient;
4914 void camera_set_velocity( vector *vel, int instantaneous )
4916 Camera_desired_velocity.xyz.x = 0.0f;
4917 Camera_desired_velocity.xyz.y = 0.0f;
4918 Camera_desired_velocity.xyz.z = 0.0f;
4920 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4921 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4922 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4924 if ( instantaneous ) {
4925 Camera_velocity = Camera_desired_velocity;
4933 vector new_vel, delta_pos;
4935 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4936 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4937 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4939 Camera_velocity = new_vel;
4941 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4943 vm_vec_add2( &Camera_pos, &delta_pos );
4945 float ot = Camera_time+0.0f;
4947 Camera_time += flFrametime;
4949 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4952 tmp.xyz.z = 4.739f; // always go this fast forward.
4954 // pick x and y velocities so they are always on a
4955 // circle with a 25 m radius.
4957 float tmp_angle = frand()*PI2;
4959 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4960 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4962 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4964 //mprintf(( "Changing velocity!\n" ));
4965 camera_set_velocity( &tmp, 0 );
4968 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4969 vector tmp = { 0.0f, 0.0f, 0.0f };
4970 camera_set_velocity( &tmp, 0 );
4975 void end_demo_campaign_do()
4977 #if defined(FS2_DEMO)
4978 // show upsell screens
4979 demo_upsell_show_screens();
4980 #elif defined(OEM_BUILD)
4981 // show oem upsell screens
4982 oem_upsell_show_screens();
4985 // drop into main hall
4986 gameseq_post_event( GS_EVENT_MAIN_MENU );
4989 // All code to process events. This is the only place
4990 // that you should change the state of the game.
4991 void game_process_event( int current_state, int event )
4993 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4996 case GS_EVENT_SIMULATOR_ROOM:
4997 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
5000 case GS_EVENT_MAIN_MENU:
5001 gameseq_set_state(GS_STATE_MAIN_MENU);
5004 case GS_EVENT_OPTIONS_MENU:
5005 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5008 case GS_EVENT_BARRACKS_MENU:
5009 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5012 case GS_EVENT_TECH_MENU:
5013 gameseq_set_state(GS_STATE_TECH_MENU);
5016 case GS_EVENT_TRAINING_MENU:
5017 gameseq_set_state(GS_STATE_TRAINING_MENU);
5020 case GS_EVENT_START_GAME:
5021 Select_default_ship = 0;
5022 Player_multi_died_check = -1;
5023 gameseq_set_state(GS_STATE_CMD_BRIEF);
5026 case GS_EVENT_START_BRIEFING:
5027 gameseq_set_state(GS_STATE_BRIEFING);
5030 case GS_EVENT_DEBRIEF:
5031 // did we end the campaign in the main freespace 2 single player campaign?
5032 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5033 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5035 gameseq_set_state(GS_STATE_DEBRIEF);
5038 Player_multi_died_check = -1;
5041 case GS_EVENT_SHIP_SELECTION:
5042 gameseq_set_state( GS_STATE_SHIP_SELECT );
5045 case GS_EVENT_WEAPON_SELECTION:
5046 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5049 case GS_EVENT_ENTER_GAME:
5051 // maybe start recording a demo
5053 demo_start_record("test.fsd");
5057 if (Game_mode & GM_MULTIPLAYER) {
5058 // if we're respawning, make sure we change the view mode so that the hud shows up
5059 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5063 gameseq_set_state(GS_STATE_GAME_PLAY);
5065 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5068 Player_multi_died_check = -1;
5070 // clear multiplayer button info
5071 extern button_info Multi_ship_status_bi;
5072 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5074 Start_time = f2fl(timer_get_approx_seconds());
5076 mprintf(("Entering game at time = %7.3f\n", Start_time));
5080 case GS_EVENT_START_GAME_QUICK:
5081 Select_default_ship = 1;
5082 gameseq_post_event(GS_EVENT_ENTER_GAME);
5086 case GS_EVENT_END_GAME:
5087 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5088 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5089 gameseq_set_state(GS_STATE_MAIN_MENU);
5094 Player_multi_died_check = -1;
5097 case GS_EVENT_QUIT_GAME:
5098 main_hall_stop_music();
5099 main_hall_stop_ambient();
5100 gameseq_set_state(GS_STATE_QUIT_GAME);
5102 Player_multi_died_check = -1;
5105 case GS_EVENT_GAMEPLAY_HELP:
5106 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5109 case GS_EVENT_PAUSE_GAME:
5110 gameseq_push_state(GS_STATE_GAME_PAUSED);
5113 case GS_EVENT_DEBUG_PAUSE_GAME:
5114 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5117 case GS_EVENT_TRAINING_PAUSE:
5118 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5121 case GS_EVENT_PREVIOUS_STATE:
5122 gameseq_pop_state();
5125 case GS_EVENT_TOGGLE_FULLSCREEN:
5126 #ifndef HARDWARE_ONLY
5128 if ( gr_screen.mode == GR_SOFTWARE ) {
5129 gr_init( GR_640, GR_DIRECTDRAW );
5130 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5131 gr_init( GR_640, GR_SOFTWARE );
5137 case GS_EVENT_TOGGLE_GLIDE:
5139 if ( gr_screen.mode != GR_GLIDE ) {
5140 gr_init( GR_640, GR_GLIDE );
5142 gr_init( GR_640, GR_SOFTWARE );
5147 case GS_EVENT_LOAD_MISSION_MENU:
5148 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5151 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5152 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5155 case GS_EVENT_HUD_CONFIG:
5156 gameseq_push_state( GS_STATE_HUD_CONFIG );
5159 case GS_EVENT_CONTROL_CONFIG:
5160 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5163 case GS_EVENT_DEATH_DIED:
5164 gameseq_set_state( GS_STATE_DEATH_DIED );
5167 case GS_EVENT_DEATH_BLEW_UP:
5168 if ( current_state == GS_STATE_DEATH_DIED ) {
5169 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5170 event_music_player_death();
5172 // multiplayer clients set their extra check here
5173 if(Game_mode & GM_MULTIPLAYER){
5174 // set the multi died absolute last chance check
5175 Player_multi_died_check = time(NULL);
5178 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5182 case GS_EVENT_NEW_CAMPAIGN:
5183 if (!mission_load_up_campaign()){
5184 readyroom_continue_campaign();
5187 Player_multi_died_check = -1;
5190 case GS_EVENT_CAMPAIGN_CHEAT:
5191 if (!mission_load_up_campaign()){
5193 // bash campaign value
5194 extern char Main_hall_campaign_cheat[512];
5197 // look for the mission
5198 for(idx=0; idx<Campaign.num_missions; idx++){
5199 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5200 Campaign.next_mission = idx;
5201 Campaign.prev_mission = idx - 1;
5208 readyroom_continue_campaign();
5211 Player_multi_died_check = -1;
5214 case GS_EVENT_CAMPAIGN_ROOM:
5215 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5218 case GS_EVENT_CMD_BRIEF:
5219 gameseq_set_state(GS_STATE_CMD_BRIEF);
5222 case GS_EVENT_RED_ALERT:
5223 gameseq_set_state(GS_STATE_RED_ALERT);
5226 case GS_EVENT_CREDITS:
5227 gameseq_set_state( GS_STATE_CREDITS );
5230 case GS_EVENT_VIEW_MEDALS:
5231 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5234 case GS_EVENT_SHOW_GOALS:
5235 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5238 case GS_EVENT_HOTKEY_SCREEN:
5239 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5242 // multiplayer stuff follow these comments
5244 case GS_EVENT_MULTI_JOIN_GAME:
5245 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5248 case GS_EVENT_MULTI_HOST_SETUP:
5249 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5252 case GS_EVENT_MULTI_CLIENT_SETUP:
5253 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5256 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5257 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5260 case GS_EVENT_MULTI_STD_WAIT:
5261 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5264 case GS_EVENT_STANDALONE_MAIN:
5265 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5268 case GS_EVENT_MULTI_PAUSE:
5269 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5272 case GS_EVENT_INGAME_PRE_JOIN:
5273 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5276 case GS_EVENT_EVENT_DEBUG:
5277 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5280 // Start a warpout where player automatically goes 70 no matter what
5281 // and can't cancel out of it.
5282 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5283 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5285 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5286 Player->saved_viewer_mode = Viewer_mode;
5287 Player->control_mode = PCM_WARPOUT_STAGE1;
5288 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5289 Warpout_time = 0.0f; // Start timer!
5292 case GS_EVENT_PLAYER_WARPOUT_START:
5293 if ( Player->control_mode != PCM_NORMAL ) {
5294 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5296 Player->saved_viewer_mode = Viewer_mode;
5297 Player->control_mode = PCM_WARPOUT_STAGE1;
5298 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5299 Warpout_time = 0.0f; // Start timer!
5300 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5304 case GS_EVENT_PLAYER_WARPOUT_STOP:
5305 if ( Player->control_mode != PCM_NORMAL ) {
5306 if ( !Warpout_forced ) { // cannot cancel forced warpout
5307 Player->control_mode = PCM_NORMAL;
5308 Viewer_mode = Player->saved_viewer_mode;
5309 hud_subspace_notify_abort();
5310 mprintf(( "Player put back to normal mode.\n" ));
5311 if ( Warpout_sound > -1 ) {
5312 snd_stop( Warpout_sound );
5319 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5320 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5321 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5322 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5324 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5325 shipfx_warpout_start( Player_obj );
5326 Player->control_mode = PCM_WARPOUT_STAGE2;
5327 Player->saved_viewer_mode = Viewer_mode;
5328 Viewer_mode |= VM_WARP_CHASE;
5330 vector tmp = Player_obj->pos;
5332 ship_get_eye( &tmp, &tmp_m, Player_obj );
5333 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5334 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5335 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5337 camera_set_position( &tmp );
5338 camera_set_orient( &Player_obj->orient );
5339 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5341 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5342 camera_set_velocity( &tmp_vel, 1);
5346 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5347 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5348 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5349 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5351 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5352 Player->control_mode = PCM_WARPOUT_STAGE3;
5356 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5357 mprintf(( "Player warped out. Going to debriefing!\n" ));
5358 Player->control_mode = PCM_NORMAL;
5359 Viewer_mode = Player->saved_viewer_mode;
5362 // we have a special debriefing screen for multiplayer furballs
5363 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5364 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5366 // do the normal debriefing for all other situations
5368 gameseq_post_event(GS_EVENT_DEBRIEF);
5372 case GS_EVENT_STANDALONE_POSTGAME:
5373 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5376 case GS_EVENT_INITIAL_PLAYER_SELECT:
5377 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5380 case GS_EVENT_GAME_INIT:
5381 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5382 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5384 // see if the command line option has been set to use the last pilot, and act acoordingly
5385 if( player_select_get_last_pilot() ) {
5386 // always enter the main menu -- do the automatic network startup stuff elsewhere
5387 // so that we still have valid checks for networking modes, etc.
5388 gameseq_set_state(GS_STATE_MAIN_MENU);
5390 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5395 case GS_EVENT_MULTI_MISSION_SYNC:
5396 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5399 case GS_EVENT_MULTI_START_GAME:
5400 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5403 case GS_EVENT_MULTI_HOST_OPTIONS:
5404 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5407 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5408 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5411 case GS_EVENT_TEAM_SELECT:
5412 gameseq_set_state(GS_STATE_TEAM_SELECT);
5415 case GS_EVENT_END_CAMPAIGN:
5416 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5419 case GS_EVENT_END_DEMO:
5420 gameseq_set_state(GS_STATE_END_DEMO);
5423 case GS_EVENT_LOOP_BRIEF:
5424 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5433 // Called when a state is being left.
5434 // The current state is still at old_state, but as soon as
5435 // this function leaves, then the current state will become
5436 // new state. You should never try to change the state
5437 // in here... if you think you need to, you probably really
5438 // need to post an event, not change the state.
5439 void game_leave_state( int old_state, int new_state )
5441 int end_mission = 1;
5443 switch (new_state) {
5444 case GS_STATE_GAME_PAUSED:
5445 case GS_STATE_DEBUG_PAUSED:
5446 case GS_STATE_OPTIONS_MENU:
5447 case GS_STATE_CONTROL_CONFIG:
5448 case GS_STATE_MISSION_LOG_SCROLLBACK:
5449 case GS_STATE_DEATH_DIED:
5450 case GS_STATE_SHOW_GOALS:
5451 case GS_STATE_HOTKEY_SCREEN:
5452 case GS_STATE_MULTI_PAUSED:
5453 case GS_STATE_TRAINING_PAUSED:
5454 case GS_STATE_EVENT_DEBUG:
5455 case GS_STATE_GAMEPLAY_HELP:
5456 end_mission = 0; // these events shouldn't end a mission
5460 switch (old_state) {
5461 case GS_STATE_BRIEFING:
5462 brief_stop_voices();
5463 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5464 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5465 && (new_state != GS_STATE_TEAM_SELECT) ){
5466 common_select_close();
5467 if ( new_state == GS_STATE_MAIN_MENU ) {
5468 freespace_stop_mission();
5472 // COMMAND LINE OPTION
5473 if (Cmdline_multi_stream_chat_to_file){
5474 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5475 cfclose(Multi_chat_stream);
5479 case GS_STATE_DEBRIEF:
5480 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5485 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5486 multi_df_debrief_close();
5489 case GS_STATE_LOAD_MISSION_MENU:
5490 mission_load_menu_close();
5493 case GS_STATE_SIMULATOR_ROOM:
5497 case GS_STATE_CAMPAIGN_ROOM:
5498 campaign_room_close();
5501 case GS_STATE_CMD_BRIEF:
5502 if (new_state == GS_STATE_OPTIONS_MENU) {
5507 if (new_state == GS_STATE_MAIN_MENU)
5508 freespace_stop_mission();
5513 case GS_STATE_RED_ALERT:
5517 case GS_STATE_SHIP_SELECT:
5518 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5519 new_state != GS_STATE_HOTKEY_SCREEN &&
5520 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5521 common_select_close();
5522 if ( new_state == GS_STATE_MAIN_MENU ) {
5523 freespace_stop_mission();
5528 case GS_STATE_WEAPON_SELECT:
5529 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5530 new_state != GS_STATE_HOTKEY_SCREEN &&
5531 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5532 common_select_close();
5533 if ( new_state == GS_STATE_MAIN_MENU ) {
5534 freespace_stop_mission();
5539 case GS_STATE_TEAM_SELECT:
5540 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5541 new_state != GS_STATE_HOTKEY_SCREEN &&
5542 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5543 common_select_close();
5544 if ( new_state == GS_STATE_MAIN_MENU ) {
5545 freespace_stop_mission();
5550 case GS_STATE_MAIN_MENU:
5551 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5558 case GS_STATE_OPTIONS_MENU:
5559 //game_start_time();
5560 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5561 multi_join_clear_game_list();
5563 options_menu_close();
5566 case GS_STATE_BARRACKS_MENU:
5567 if(new_state != GS_STATE_VIEW_MEDALS){
5572 case GS_STATE_MISSION_LOG_SCROLLBACK:
5573 hud_scrollback_close();
5576 case GS_STATE_TRAINING_MENU:
5577 training_menu_close();
5580 case GS_STATE_GAME_PLAY:
5581 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5582 player_save_target_and_weapon_link_prefs();
5583 game_stop_looped_sounds();
5586 sound_env_disable();
5587 joy_ff_stop_effects();
5589 // stop game time under certain conditions
5590 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5595 // shut down any recording or playing demos
5600 // when in multiplayer and going back to the main menu, send a leave game packet
5601 // right away (before calling stop mission). stop_mission was taking to long to
5602 // close mission down and I want people to get notified ASAP.
5603 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5604 multi_quit_game(PROMPT_NONE);
5607 freespace_stop_mission();
5608 Game_time_compression = F1_0;
5612 case GS_STATE_TECH_MENU:
5616 case GS_STATE_TRAINING_PAUSED:
5617 Training_num_lines = 0;
5618 // fall through to GS_STATE_GAME_PAUSED
5620 case GS_STATE_GAME_PAUSED:
5622 if ( end_mission ) {
5627 case GS_STATE_DEBUG_PAUSED:
5630 pause_debug_close();
5634 case GS_STATE_HUD_CONFIG:
5638 // join/start a game
5639 case GS_STATE_MULTI_JOIN_GAME:
5640 if(new_state != GS_STATE_OPTIONS_MENU){
5641 multi_join_game_close();
5645 case GS_STATE_MULTI_HOST_SETUP:
5646 case GS_STATE_MULTI_CLIENT_SETUP:
5647 // if this is just the host going into the options screen, don't do anything
5648 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5652 // close down the proper state
5653 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5654 multi_create_game_close();
5656 multi_game_client_setup_close();
5659 // COMMAND LINE OPTION
5660 if (Cmdline_multi_stream_chat_to_file){
5661 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5662 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5663 cfclose(Multi_chat_stream);
5668 case GS_STATE_CONTROL_CONFIG:
5669 control_config_close();
5672 case GS_STATE_DEATH_DIED:
5673 Game_mode &= ~GM_DEAD_DIED;
5675 // early end while respawning or blowing up in a multiplayer game
5676 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5678 freespace_stop_mission();
5682 case GS_STATE_DEATH_BLEW_UP:
5683 Game_mode &= ~GM_DEAD_BLEW_UP;
5685 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5686 // to determine if I should do anything.
5687 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5689 freespace_stop_mission();
5692 // if we are not respawing as an observer or as a player, our new state will not
5693 // be gameplay state.
5694 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5695 game_stop_time(); // hasn't been called yet!!
5696 freespace_stop_mission();
5702 case GS_STATE_CREDITS:
5706 case GS_STATE_VIEW_MEDALS:
5710 case GS_STATE_SHOW_GOALS:
5711 mission_show_goals_close();
5714 case GS_STATE_HOTKEY_SCREEN:
5715 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5716 mission_hotkey_close();
5720 case GS_STATE_MULTI_MISSION_SYNC:
5721 // if we're moving into the options menu, don't do anything
5722 if(new_state == GS_STATE_OPTIONS_MENU){
5726 Assert( Game_mode & GM_MULTIPLAYER );
5728 if ( new_state == GS_STATE_GAME_PLAY ){
5729 // palette_restore_palette();
5731 // change a couple of flags to indicate our state!!!
5732 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5733 send_netplayer_update_packet();
5735 // set the game mode
5736 Game_mode |= GM_IN_MISSION;
5740 case GS_STATE_VIEW_CUTSCENES:
5741 cutscenes_screen_close();
5744 case GS_STATE_MULTI_STD_WAIT:
5745 multi_standalone_wait_close();
5748 case GS_STATE_STANDALONE_MAIN:
5749 standalone_main_close();
5750 if(new_state == GS_STATE_MULTI_STD_WAIT){
5751 init_multiplayer_stats();
5755 case GS_STATE_MULTI_PAUSED:
5756 // if ( end_mission ){
5761 case GS_STATE_INGAME_PRE_JOIN:
5762 multi_ingame_select_close();
5765 case GS_STATE_STANDALONE_POSTGAME:
5766 multi_standalone_postgame_close();
5769 case GS_STATE_INITIAL_PLAYER_SELECT:
5770 player_select_close();
5773 case GS_STATE_MULTI_START_GAME:
5774 multi_start_game_close();
5777 case GS_STATE_MULTI_HOST_OPTIONS:
5778 multi_host_options_close();
5781 case GS_STATE_END_OF_CAMPAIGN:
5782 mission_campaign_end_close();
5785 case GS_STATE_LOOP_BRIEF:
5791 // Called when a state is being entered.
5792 // The current state is set to the state we're entering at
5793 // this point, and old_state is set to the state we're coming
5794 // from. You should never try to change the state
5795 // in here... if you think you need to, you probably really
5796 // need to post an event, not change the state.
5798 void game_enter_state( int old_state, int new_state )
5800 switch (new_state) {
5801 case GS_STATE_MAIN_MENU:
5802 // in multiplayer mode, be sure that we are not doing networking anymore.
5803 if ( Game_mode & GM_MULTIPLAYER ) {
5804 Assert( Net_player != NULL );
5805 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5808 Game_time_compression = F1_0;
5810 // determine which ship this guy is currently based on
5811 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5814 if (Player->on_bastion) {
5822 case GS_STATE_BRIEFING:
5823 main_hall_stop_music();
5824 main_hall_stop_ambient();
5826 if (Game_mode & GM_NORMAL) {
5827 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5828 // MWA: or from options or hotkey screens
5829 // JH: or if the command brief state already did this
5830 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5831 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5832 && (old_state != GS_STATE_CMD_BRIEF) ) {
5833 if ( !game_start_mission() ) // this should put us into a new state on failure!
5837 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5838 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5839 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5841 Game_time_compression = F1_0;
5843 if ( red_alert_mission() ) {
5844 gameseq_post_event(GS_EVENT_RED_ALERT);
5851 case GS_STATE_DEBRIEF:
5852 game_stop_looped_sounds();
5853 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5854 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5859 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5860 multi_df_debrief_init();
5863 case GS_STATE_LOAD_MISSION_MENU:
5864 mission_load_menu_init();
5867 case GS_STATE_SIMULATOR_ROOM:
5871 case GS_STATE_CAMPAIGN_ROOM:
5872 campaign_room_init();
5875 case GS_STATE_RED_ALERT:
5876 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5880 case GS_STATE_CMD_BRIEF: {
5881 int team_num = 0; // team number used as index for which cmd brief to use.
5883 if (old_state == GS_STATE_OPTIONS_MENU) {
5887 main_hall_stop_music();
5888 main_hall_stop_ambient();
5890 if (Game_mode & GM_NORMAL) {
5891 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5892 // MWA: or from options or hotkey screens
5893 // JH: or if the command brief state already did this
5894 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5895 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5896 if ( !game_start_mission() ) // this should put us into a new state on failure!
5901 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5902 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5903 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5905 cmd_brief_init(team_num);
5911 case GS_STATE_SHIP_SELECT:
5915 case GS_STATE_WEAPON_SELECT:
5916 weapon_select_init();
5919 case GS_STATE_TEAM_SELECT:
5923 case GS_STATE_GAME_PAUSED:
5928 case GS_STATE_DEBUG_PAUSED:
5929 // game_stop_time();
5930 // os_set_title("FreeSpace - PAUSED");
5933 case GS_STATE_TRAINING_PAUSED:
5940 case GS_STATE_OPTIONS_MENU:
5942 options_menu_init();
5945 case GS_STATE_GAME_PLAY:
5946 // coming from the gameplay state or the main menu, we might need to load the mission
5947 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5948 if ( !game_start_mission() ) // this should put us into a new state.
5953 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5954 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5955 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5956 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5957 (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) ) {
5958 // JAS: Used to do all paging here.
5962 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5966 main_hall_stop_music();
5967 main_hall_stop_ambient();
5968 event_music_first_pattern(); // start the first pattern
5971 // special code that restores player ship selection and weapons loadout when doing a quick start
5972 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5973 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5974 wss_direct_restore_loadout();
5978 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5979 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5980 event_music_first_pattern(); // start the first pattern
5983 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5984 event_music_first_pattern(); // start the first pattern
5986 player_restore_target_and_weapon_link_prefs();
5988 Game_mode |= GM_IN_MISSION;
5991 // required to truely make mouse deltas zeroed in debug mouse code
5992 void mouse_force_pos(int x, int y);
5993 if (!Is_standalone) {
5994 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
6000 // only start time if in single player, or coming from multi wait state
6003 (Game_mode & GM_NORMAL) &&
6004 (old_state != GS_STATE_VIEW_CUTSCENES)
6006 (Game_mode & GM_MULTIPLAYER) && (
6007 (old_state == GS_STATE_MULTI_PAUSED) ||
6008 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6014 // when coming from the multi paused state, reset the timestamps
6015 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6016 multi_reset_timestamps();
6019 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6020 // initialize all object update details
6021 multi_oo_gameplay_init();
6024 // under certain circumstances, the server should reset the object update rate limiting stuff
6025 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6026 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6028 // reinitialize the rate limiting system for all clients
6029 multi_oo_rate_init_all();
6032 // multiplayer clients should always re-initialize their control info rate limiting system
6033 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6034 multi_oo_rate_init_all();
6038 if(Game_mode & GM_MULTIPLAYER){
6039 multi_ping_reset_players();
6042 Game_subspace_effect = 0;
6043 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6044 Game_subspace_effect = 1;
6045 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6046 game_start_subspace_ambient_sound();
6050 sound_env_set(&Game_sound_env);
6051 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6053 // clear multiplayer button info i
6054 extern button_info Multi_ship_status_bi;
6055 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6058 case GS_STATE_HUD_CONFIG:
6062 case GS_STATE_MULTI_JOIN_GAME:
6063 multi_join_clear_game_list();
6065 if (old_state != GS_STATE_OPTIONS_MENU) {
6066 multi_join_game_init();
6071 case GS_STATE_MULTI_HOST_SETUP:
6072 // don't reinitialize if we're coming back from the host options screen
6073 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6074 multi_create_game_init();
6079 case GS_STATE_MULTI_CLIENT_SETUP:
6080 if (old_state != GS_STATE_OPTIONS_MENU) {
6081 multi_game_client_setup_init();
6086 case GS_STATE_CONTROL_CONFIG:
6087 control_config_init();
6090 case GS_STATE_TECH_MENU:
6094 case GS_STATE_BARRACKS_MENU:
6095 if(old_state != GS_STATE_VIEW_MEDALS){
6100 case GS_STATE_MISSION_LOG_SCROLLBACK:
6101 hud_scrollback_init();
6104 case GS_STATE_DEATH_DIED:
6105 Player_died_time = timestamp(10);
6107 if(!(Game_mode & GM_MULTIPLAYER)){
6108 player_show_death_message();
6110 Game_mode |= GM_DEAD_DIED;
6113 case GS_STATE_DEATH_BLEW_UP:
6114 if ( !popupdead_is_active() ) {
6115 Player_ai->target_objnum = -1;
6118 // stop any local EMP effect
6121 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6122 Game_mode |= GM_DEAD_BLEW_UP;
6123 Show_viewing_from_self = 0;
6125 // timestamp how long we should wait before displaying the died popup
6126 if ( !popupdead_is_active() ) {
6127 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6131 case GS_STATE_GAMEPLAY_HELP:
6132 gameplay_help_init();
6135 case GS_STATE_CREDITS:
6136 main_hall_stop_music();
6137 main_hall_stop_ambient();
6141 case GS_STATE_VIEW_MEDALS:
6142 medal_main_init(Player);
6145 case GS_STATE_SHOW_GOALS:
6146 mission_show_goals_init();
6149 case GS_STATE_HOTKEY_SCREEN:
6150 mission_hotkey_init();
6153 case GS_STATE_MULTI_MISSION_SYNC:
6154 // if we're coming from the options screen, don't do any
6155 if(old_state == GS_STATE_OPTIONS_MENU){
6159 switch(Multi_sync_mode){
6160 case MULTI_SYNC_PRE_BRIEFING:
6161 // if moving from game forming to the team select state
6164 case MULTI_SYNC_POST_BRIEFING:
6165 // if moving from briefing into the mission itself
6168 // tell everyone that we're now loading data
6169 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6170 send_netplayer_update_packet();
6172 // JAS: Used to do all paging here!!!!
6174 Net_player->state = NETPLAYER_STATE_WAITING;
6175 send_netplayer_update_packet();
6177 Game_time_compression = F1_0;
6179 case MULTI_SYNC_INGAME:
6185 case GS_STATE_VIEW_CUTSCENES:
6186 cutscenes_screen_init();
6189 case GS_STATE_MULTI_STD_WAIT:
6190 multi_standalone_wait_init();
6193 case GS_STATE_STANDALONE_MAIN:
6194 // don't initialize if we're coming from one of these 2 states unless there are no
6195 // players left (reset situation)
6196 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6197 standalone_main_init();
6201 case GS_STATE_MULTI_PAUSED:
6205 case GS_STATE_INGAME_PRE_JOIN:
6206 multi_ingame_select_init();
6209 case GS_STATE_STANDALONE_POSTGAME:
6210 multi_standalone_postgame_init();
6213 case GS_STATE_INITIAL_PLAYER_SELECT:
6214 player_select_init();
6217 case GS_STATE_MULTI_START_GAME:
6218 multi_start_game_init();
6221 case GS_STATE_MULTI_HOST_OPTIONS:
6222 multi_host_options_init();
6225 case GS_STATE_END_OF_CAMPAIGN:
6226 mission_campaign_end_init();
6229 case GS_STATE_LOOP_BRIEF:
6236 // do stuff that may need to be done regardless of state
6237 void game_do_state_common(int state,int no_networking)
6239 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6240 snd_do_frame(); // update sound system
6241 event_music_do_frame(); // music needs to play across many states
6243 multi_log_process();
6245 if (no_networking) {
6249 // maybe do a multiplayer frame based on game mode and state type
6250 if (Game_mode & GM_MULTIPLAYER) {
6252 case GS_STATE_OPTIONS_MENU:
6253 case GS_STATE_GAMEPLAY_HELP:
6254 case GS_STATE_HOTKEY_SCREEN:
6255 case GS_STATE_HUD_CONFIG:
6256 case GS_STATE_CONTROL_CONFIG:
6257 case GS_STATE_MISSION_LOG_SCROLLBACK:
6258 case GS_STATE_SHOW_GOALS:
6259 case GS_STATE_VIEW_CUTSCENES:
6260 case GS_STATE_EVENT_DEBUG:
6261 multi_maybe_do_frame();
6265 game_do_networking();
6269 // Called once a frame.
6270 // You should never try to change the state
6271 // in here... if you think you need to, you probably really
6272 // need to post an event, not change the state.
6273 int Game_do_state_should_skip = 0;
6274 void game_do_state(int state)
6276 // always lets the do_state_common() function determine if the state should be skipped
6277 Game_do_state_should_skip = 0;
6279 // legal to set the should skip state anywhere in this function
6280 game_do_state_common(state); // do stuff that may need to be done regardless of state
6282 if(Game_do_state_should_skip){
6287 case GS_STATE_MAIN_MENU:
6288 game_set_frametime(GS_STATE_MAIN_MENU);
6289 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6292 main_hall_do(flFrametime);
6296 case GS_STATE_OPTIONS_MENU:
6297 game_set_frametime(GS_STATE_OPTIONS_MENU);
6298 options_menu_do_frame(flFrametime);
6301 case GS_STATE_BARRACKS_MENU:
6302 game_set_frametime(GS_STATE_BARRACKS_MENU);
6303 barracks_do_frame(flFrametime);
6306 case GS_STATE_TRAINING_MENU:
6307 game_set_frametime(GS_STATE_TRAINING_MENU);
6308 training_menu_do_frame(flFrametime);
6311 case GS_STATE_TECH_MENU:
6312 game_set_frametime(GS_STATE_TECH_MENU);
6313 techroom_do_frame(flFrametime);
6316 case GS_STATE_GAMEPLAY_HELP:
6317 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6318 gameplay_help_do_frame(flFrametime);
6321 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6325 case GS_STATE_GAME_PAUSED:
6329 case GS_STATE_DEBUG_PAUSED:
6331 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6336 case GS_STATE_TRAINING_PAUSED:
6337 game_training_pause_do();
6340 case GS_STATE_LOAD_MISSION_MENU:
6341 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6342 mission_load_menu_do();
6345 case GS_STATE_BRIEFING:
6346 game_set_frametime(GS_STATE_BRIEFING);
6347 brief_do_frame(flFrametime);
6350 case GS_STATE_DEBRIEF:
6351 game_set_frametime(GS_STATE_DEBRIEF);
6352 debrief_do_frame(flFrametime);
6355 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6356 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6357 multi_df_debrief_do();
6360 case GS_STATE_SHIP_SELECT:
6361 game_set_frametime(GS_STATE_SHIP_SELECT);
6362 ship_select_do(flFrametime);
6365 case GS_STATE_WEAPON_SELECT:
6366 game_set_frametime(GS_STATE_WEAPON_SELECT);
6367 weapon_select_do(flFrametime);
6370 case GS_STATE_MISSION_LOG_SCROLLBACK:
6371 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6372 hud_scrollback_do_frame(flFrametime);
6375 case GS_STATE_HUD_CONFIG:
6376 game_set_frametime(GS_STATE_HUD_CONFIG);
6377 hud_config_do_frame(flFrametime);
6380 case GS_STATE_MULTI_JOIN_GAME:
6381 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6382 multi_join_game_do_frame();
6385 case GS_STATE_MULTI_HOST_SETUP:
6386 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6387 multi_create_game_do();
6390 case GS_STATE_MULTI_CLIENT_SETUP:
6391 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6392 multi_game_client_setup_do_frame();
6395 case GS_STATE_CONTROL_CONFIG:
6396 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6397 control_config_do_frame(flFrametime);
6400 case GS_STATE_DEATH_DIED:
6404 case GS_STATE_DEATH_BLEW_UP:
6408 case GS_STATE_SIMULATOR_ROOM:
6409 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6410 sim_room_do_frame(flFrametime);
6413 case GS_STATE_CAMPAIGN_ROOM:
6414 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6415 campaign_room_do_frame(flFrametime);
6418 case GS_STATE_RED_ALERT:
6419 game_set_frametime(GS_STATE_RED_ALERT);
6420 red_alert_do_frame(flFrametime);
6423 case GS_STATE_CMD_BRIEF:
6424 game_set_frametime(GS_STATE_CMD_BRIEF);
6425 cmd_brief_do_frame(flFrametime);
6428 case GS_STATE_CREDITS:
6429 game_set_frametime(GS_STATE_CREDITS);
6430 credits_do_frame(flFrametime);
6433 case GS_STATE_VIEW_MEDALS:
6434 game_set_frametime(GS_STATE_VIEW_MEDALS);
6438 case GS_STATE_SHOW_GOALS:
6439 game_set_frametime(GS_STATE_SHOW_GOALS);
6440 mission_show_goals_do_frame(flFrametime);
6443 case GS_STATE_HOTKEY_SCREEN:
6444 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6445 mission_hotkey_do_frame(flFrametime);
6448 case GS_STATE_VIEW_CUTSCENES:
6449 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6450 cutscenes_screen_do_frame();
6453 case GS_STATE_MULTI_STD_WAIT:
6454 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6455 multi_standalone_wait_do();
6458 case GS_STATE_STANDALONE_MAIN:
6459 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6460 standalone_main_do();
6463 case GS_STATE_MULTI_PAUSED:
6464 game_set_frametime(GS_STATE_MULTI_PAUSED);
6468 case GS_STATE_TEAM_SELECT:
6469 game_set_frametime(GS_STATE_TEAM_SELECT);
6473 case GS_STATE_INGAME_PRE_JOIN:
6474 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6475 multi_ingame_select_do();
6478 case GS_STATE_EVENT_DEBUG:
6480 game_set_frametime(GS_STATE_EVENT_DEBUG);
6481 game_show_event_debug(flFrametime);
6485 case GS_STATE_STANDALONE_POSTGAME:
6486 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6487 multi_standalone_postgame_do();
6490 case GS_STATE_INITIAL_PLAYER_SELECT:
6491 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6495 case GS_STATE_MULTI_MISSION_SYNC:
6496 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6500 case GS_STATE_MULTI_START_GAME:
6501 game_set_frametime(GS_STATE_MULTI_START_GAME);
6502 multi_start_game_do();
6505 case GS_STATE_MULTI_HOST_OPTIONS:
6506 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6507 multi_host_options_do();
6510 case GS_STATE_END_OF_CAMPAIGN:
6511 mission_campaign_end_do();
6514 case GS_STATE_END_DEMO:
6515 game_set_frametime(GS_STATE_END_DEMO);
6516 end_demo_campaign_do();
6519 case GS_STATE_LOOP_BRIEF:
6520 game_set_frametime(GS_STATE_LOOP_BRIEF);
6524 } // end switch(gs_current_state)
6528 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6529 int game_do_ram_check(int ram_in_bytes)
6531 if ( ram_in_bytes < 30*1024*1024 ) {
6532 int allowed_to_run = 1;
6533 if ( ram_in_bytes < 25*1024*1024 ) {
6538 int Freespace_total_ram_MB;
6539 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6541 if ( allowed_to_run ) {
6543 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);
6548 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6549 if ( msgbox_rval == IDCANCEL ) {
6556 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);
6558 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6569 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6570 // If so, copy it over and remove the update directory.
6571 void game_maybe_update_launcher(char *exe_dir)
6574 char src_filename[MAX_PATH];
6575 char dest_filename[MAX_PATH];
6577 strcpy(src_filename, exe_dir);
6578 strcat(src_filename, NOX("\\update\\freespace.exe"));
6580 strcpy(dest_filename, exe_dir);
6581 strcat(dest_filename, NOX("\\freespace.exe"));
6583 // see if src_filename exists
6585 fp = fopen(src_filename, "rb");
6591 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6593 // copy updated freespace.exe to freespace exe dir
6594 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6595 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 );
6599 // delete the file in the update directory
6600 DeleteFile(src_filename);
6602 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6603 char update_dir[MAX_PATH];
6604 strcpy(update_dir, exe_dir);
6605 strcat(update_dir, NOX("\\update"));
6606 RemoveDirectory(update_dir);
6612 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6616 int sub_total_destroyed = 0;
6620 // get the total for all his children
6621 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6622 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6625 // find the # of faces for this _individual_ object
6626 total = submodel_get_num_polys(model_num, sm);
6627 if(strstr(pm->submodel[sm].name, "-destroyed")){
6628 sub_total_destroyed = total;
6632 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6635 *out_total += total + sub_total;
6636 *out_destroyed_total += sub_total_destroyed;
6639 #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);
6640 void game_spew_pof_info()
6642 char *pof_list[1000];
6645 int idx, model_num, i, j;
6647 int total, root_total, model_total, destroyed_total, counted;
6651 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6653 // spew info on all the pofs
6659 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6664 for(idx=0; idx<num_files; idx++, counted++){
6665 sprintf(str, "%s.pof", pof_list[idx]);
6666 model_num = model_load(str, 0, NULL);
6668 pm = model_get(model_num);
6670 // if we have a real model
6675 // go through and print all raw submodels
6676 cfputs("RAW\n", out);
6679 for (i=0; i<pm->n_models; i++) {
6680 total = submodel_get_num_polys(model_num, i);
6682 model_total += total;
6683 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6686 sprintf(str, "Model total %d\n", model_total);
6689 // now go through and do it by LOD
6690 cfputs("BY LOD\n\n", out);
6691 for(i=0; i<pm->n_detail_levels; i++){
6692 sprintf(str, "LOD %d\n", i);
6696 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6698 destroyed_total = 0;
6699 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6700 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6703 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6706 sprintf(str, "TOTAL: %d\n", total + root_total);
6708 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6710 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6713 cfputs("------------------------------------------------------------------------\n\n", out);
6717 if(counted >= MAX_POLYGON_MODELS - 5){
6730 game_spew_pof_info();
6733 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6738 // Don't let more than one instance of Freespace run.
6739 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6741 SetForegroundWindow(hwnd);
6746 // Find out how much RAM is on this machine
6749 ms.dwLength = sizeof(MEMORYSTATUS);
6750 GlobalMemoryStatus(&ms);
6751 Freespace_total_ram = ms.dwTotalPhys;
6753 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6757 if ( ms.dwTotalVirtual < 1024 ) {
6758 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6762 if (!vm_init(24*1024*1024)) {
6763 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 );
6767 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6769 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);
6777 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6778 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6779 seem worth bothering with.
6783 lResult = RegOpenKeyEx(
6784 HKEY_LOCAL_MACHINE, // Where it is
6785 "Software\\Microsoft\\DirectX", // name of key
6786 NULL, // DWORD reserved
6787 KEY_QUERY_VALUE, // Allows all changes
6788 &hKey // Location to store key
6791 if (lResult == ERROR_SUCCESS) {
6793 DWORD dwType, dwLen;
6796 lResult = RegQueryValueEx(
6797 hKey, // Handle to key
6798 "Version", // The values name
6799 NULL, // DWORD reserved
6800 &dwType, // What kind it is
6801 (ubyte *) version, // value to set
6802 &dwLen // How many bytes to set
6805 if (lResult == ERROR_SUCCESS) {
6806 dx_version = atoi(strstr(version, ".") + 1);
6810 DWORD dwType, dwLen;
6813 lResult = RegQueryValueEx(
6814 hKey, // Handle to key
6815 "InstalledVersion", // The values name
6816 NULL, // DWORD reserved
6817 &dwType, // What kind it is
6818 (ubyte *) &val, // value to set
6819 &dwLen // How many bytes to set
6822 if (lResult == ERROR_SUCCESS) {
6830 if (dx_version < 3) {
6831 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6832 "latest version of DirectX at:\n\n"
6833 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6835 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6836 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6841 //=====================================================
6842 // Make sure we're running in the right directory.
6846 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6847 char *p = exe_dir + strlen(exe_dir);
6849 // chop off the filename
6850 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6856 if ( strlen(exe_dir) > 0 ) {
6857 SetCurrentDirectory(exe_dir);
6860 // check for updated freespace.exe
6861 game_maybe_update_launcher(exe_dir);
6869 extern void windebug_memwatch_init();
6870 windebug_memwatch_init();
6874 parse_cmdline(szCmdLine);
6876 #ifdef STANDALONE_ONLY_BUILD
6878 nprintf(("Network", "Standalone running"));
6881 nprintf(("Network", "Standalone running"));
6889 // maybe spew pof stuff
6890 if(Cmdline_spew_pof_info){
6891 game_spew_pof_info();
6896 // non-demo, non-standalone, play the intro movie
6901 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) ){
6903 #if defined(OEM_BUILD)
6904 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6906 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6907 #endif // defined(OEM_BUILD)
6912 if ( !Is_standalone ) {
6914 // release -- movies always play
6917 // 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
6918 movie_play( NOX("intro.mve"), 0 );
6920 // debug version, movie will only play with -showmovies
6921 #elif !defined(NDEBUG)
6923 movie_play( NOX("intro.mve"), 0);
6926 if ( Cmdline_show_movies )
6927 movie_play( NOX("intro.mve"), 0 );
6936 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6938 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6942 // only important for non THREADED mode
6945 state = gameseq_process_events();
6946 if ( state == GS_STATE_QUIT_GAME ){
6953 demo_upsell_show_screens();
6955 #elif defined(OEM_BUILD)
6956 // show upsell screens on exit
6957 oem_upsell_show_screens();
6964 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6970 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6972 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6974 // Do nothing here - RecordExceptionInfo() has already done
6975 // everything that is needed. Actually this code won't even
6976 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6977 // the __except clause.
6981 nprintf(("WinMain", "exceptions shall fall through"));
6983 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6989 // launcher the fslauncher program on exit
6990 void game_launch_launcher_on_exit()
6994 PROCESS_INFORMATION pi;
6995 char cmd_line[2048];
6996 char original_path[1024] = "";
6998 memset( &si, 0, sizeof(STARTUPINFO) );
7002 _getcwd(original_path, 1023);
7004 // set up command line
7005 strcpy(cmd_line, original_path);
7006 strcat(cmd_line, "\\");
7007 strcat(cmd_line, LAUNCHER_FNAME);
7008 strcat(cmd_line, " -straight_to_update");
7010 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7011 cmd_line, // pointer to command line string
7012 NULL, // pointer to process security attributes
7013 NULL, // pointer to thread security attributes
7014 FALSE, // handle inheritance flag
7015 CREATE_DEFAULT_ERROR_MODE, // creation flags
7016 NULL, // pointer to new environment block
7017 NULL, // pointer to current directory name
7018 &si, // pointer to STARTUPINFO
7019 &pi // pointer to PROCESS_INFORMATION
7021 // to eliminate build warnings
7031 // This function is called when FreeSpace terminates normally.
7033 void game_shutdown(void)
7039 // don't ever flip a page on the standalone!
7040 if(!(Game_mode & GM_STANDALONE_SERVER)){
7046 // if the player has left the "player select" screen and quit the game without actually choosing
7047 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7048 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7052 // load up common multiplayer icons
7053 multi_unload_common_icons();
7055 shockwave_close(); // release any memory used by shockwave system
7056 fireball_close(); // free fireball system
7057 ship_close(); // free any memory that was allocated for the ships
7058 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7059 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7060 bm_unload_all(); // free bitmaps
7061 mission_campaign_close(); // close out the campaign stuff
7062 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7064 #ifdef MULTI_USE_LAG
7068 // the menu close functions will unload the bitmaps if they were displayed during the game
7069 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7072 training_menu_close();
7075 extern void joy_close();
7078 audiostream_close();
7080 event_music_close();
7084 // HACKITY HACK HACK
7085 // if this flag is set, we should be firing up the launcher when exiting freespace
7086 extern int Multi_update_fireup_launcher_on_exit;
7087 if(Multi_update_fireup_launcher_on_exit){
7088 game_launch_launcher_on_exit();
7092 // game_stop_looped_sounds()
7094 // This function will call the appropriate stop looped sound functions for those
7095 // modules which use looping sounds. It is not enough just to stop a looping sound
7096 // at the DirectSound level, the game is keeping track of looping sounds, and this
7097 // function is used to inform the game that looping sounds are being halted.
7099 void game_stop_looped_sounds()
7101 hud_stop_looped_locking_sounds();
7102 hud_stop_looped_engine_sounds();
7103 afterburner_stop_sounds();
7104 player_stop_looped_sounds();
7105 obj_snd_stop_all(); // stop all object-linked persistant sounds
7106 game_stop_subspace_ambient_sound();
7107 snd_stop(Radar_static_looping);
7108 Radar_static_looping = -1;
7109 snd_stop(Target_static_looping);
7110 shipfx_stop_engine_wash_sound();
7111 Target_static_looping = -1;
7114 //////////////////////////////////////////////////////////////////////////
7116 // Code for supporting an animating mouse pointer
7119 //////////////////////////////////////////////////////////////////////////
7121 typedef struct animating_obj
7130 static animating_obj Animating_mouse;
7132 // ----------------------------------------------------------------------------
7133 // init_animating_pointer()
7135 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7136 // gets properly initialized
7138 void init_animating_pointer()
7140 Animating_mouse.first_frame = -1;
7141 Animating_mouse.num_frames = 0;
7142 Animating_mouse.current_frame = -1;
7143 Animating_mouse.time = 0.0f;
7144 Animating_mouse.elapsed_time = 0.0f;
7147 // ----------------------------------------------------------------------------
7148 // load_animating_pointer()
7150 // Called at game init to load in the frames for the animating mouse pointer
7152 // input: filename => filename of animation file that holds the animation
7154 void load_animating_pointer(char *filename, int dx, int dy)
7159 init_animating_pointer();
7161 am = &Animating_mouse;
7162 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7163 if ( am->first_frame == -1 )
7164 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7165 am->current_frame = 0;
7166 am->time = am->num_frames / i2fl(fps);
7169 // ----------------------------------------------------------------------------
7170 // unload_animating_pointer()
7172 // Called at game shutdown to free the memory used to store the animation frames
7174 void unload_animating_pointer()
7179 am = &Animating_mouse;
7180 for ( i = 0; i < am->num_frames; i++ ) {
7181 Assert( (am->first_frame+i) >= 0 );
7182 bm_release(am->first_frame + i);
7185 am->first_frame = -1;
7187 am->current_frame = -1;
7190 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7191 void game_render_mouse(float frametime)
7196 // if animating cursor exists, play the next frame
7197 am = &Animating_mouse;
7198 if ( am->first_frame != -1 ) {
7199 mouse_get_pos(&mx, &my);
7200 am->elapsed_time += frametime;
7201 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7202 if ( am->current_frame >= am->num_frames ) {
7203 am->current_frame = 0;
7204 am->elapsed_time = 0.0f;
7206 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7210 // ----------------------------------------------------------------------------
7211 // game_maybe_draw_mouse()
7213 // determines whether to draw the mouse pointer at all, and what frame of
7214 // animation to use if the mouse is animating
7216 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7218 // input: frametime => elapsed frame time in seconds since last call
7220 void game_maybe_draw_mouse(float frametime)
7224 game_state = gameseq_get_state();
7226 switch ( game_state ) {
7227 case GS_STATE_GAME_PAUSED:
7228 // case GS_STATE_MULTI_PAUSED:
7229 case GS_STATE_GAME_PLAY:
7230 case GS_STATE_DEATH_DIED:
7231 case GS_STATE_DEATH_BLEW_UP:
7232 if ( popup_active() || popupdead_is_active() ) {
7244 if ( !Mouse_hidden )
7245 game_render_mouse(frametime);
7249 void game_do_training_checks()
7253 waypoint_list *wplp;
7255 if (Training_context & TRAINING_CONTEXT_SPEED) {
7256 s = (int) Player_obj->phys_info.fspeed;
7257 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7258 if (!Training_context_speed_set) {
7259 Training_context_speed_set = 1;
7260 Training_context_speed_timestamp = timestamp();
7264 Training_context_speed_set = 0;
7267 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7268 wplp = &Waypoint_lists[Training_context_path];
7269 if (wplp->count > Training_context_goal_waypoint) {
7270 i = Training_context_goal_waypoint;
7272 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7273 if (d <= Training_context_distance) {
7274 Training_context_at_waypoint = i;
7275 if (Training_context_goal_waypoint == i) {
7276 Training_context_goal_waypoint++;
7277 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7284 if (i == wplp->count)
7287 } while (i != Training_context_goal_waypoint);
7291 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7292 Players_target = Player_ai->target_objnum;
7293 Players_targeted_subsys = Player_ai->targeted_subsys;
7294 Players_target_timestamp = timestamp();
7298 /////////// Following is for event debug view screen
7302 #define EVENT_DEBUG_MAX 5000
7303 #define EVENT_DEBUG_EVENT 0x8000
7305 int Event_debug_index[EVENT_DEBUG_MAX];
7308 void game_add_event_debug_index(int n, int indent)
7310 if (ED_count < EVENT_DEBUG_MAX)
7311 Event_debug_index[ED_count++] = n | (indent << 16);
7314 void game_add_event_debug_sexp(int n, int indent)
7319 if (Sexp_nodes[n].first >= 0) {
7320 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7321 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7325 game_add_event_debug_index(n, indent);
7326 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7327 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7329 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7332 void game_event_debug_init()
7337 for (e=0; e<Num_mission_events; e++) {
7338 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7339 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7343 void game_show_event_debug(float frametime)
7347 int font_height, font_width;
7349 static int scroll_offset = 0;
7351 k = game_check_key();
7357 if (scroll_offset < 0)
7367 scroll_offset -= 20;
7368 if (scroll_offset < 0)
7373 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7377 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7383 gr_set_color_fast(&Color_bright);
7385 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7387 gr_set_color_fast(&Color_normal);
7389 gr_get_string_size(&font_width, &font_height, NOX("test"));
7390 y_max = gr_screen.max_h - font_height - 5;
7394 while (k < ED_count) {
7395 if (y_index > y_max)
7398 z = Event_debug_index[k];
7399 if (z & EVENT_DEBUG_EVENT) {
7401 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7402 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7403 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7404 Mission_events[z].repeat_count, Mission_events[z].interval);
7412 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7413 switch (Sexp_nodes[z & 0x7fff].value) {
7415 strcat(buf, NOX(" (True)"));
7419 strcat(buf, NOX(" (False)"));
7422 case SEXP_KNOWN_TRUE:
7423 strcat(buf, NOX(" (Always true)"));
7426 case SEXP_KNOWN_FALSE:
7427 strcat(buf, NOX(" (Always false)"));
7430 case SEXP_CANT_EVAL:
7431 strcat(buf, NOX(" (Can't eval)"));
7435 case SEXP_NAN_FOREVER:
7436 strcat(buf, NOX(" (Not a number)"));
7441 gr_printf(10, y_index, buf);
7442 y_index += font_height;
7455 extern int Tmap_npixels;
7457 int Tmap_num_too_big = 0;
7458 int Num_models_needing_splitting = 0;
7460 void Time_model( int modelnum )
7462 // mprintf(( "Timing ship '%s'\n", si->name ));
7464 vector eye_pos, model_pos;
7465 matrix eye_orient, model_orient;
7467 polymodel *pm = model_get( modelnum );
7469 int l = strlen(pm->filename);
7471 if ( (l == '/') || (l=='\\') || (l==':')) {
7477 char *pof_file = &pm->filename[l];
7479 int model_needs_splitting = 0;
7481 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7483 for (i=0; i<pm->n_textures; i++ ) {
7484 char filename[1024];
7487 int bmp_num = pm->original_textures[i];
7488 if ( bmp_num > -1 ) {
7489 bm_get_palette(pm->original_textures[i], pal, filename );
7491 bm_get_info( pm->original_textures[i],&w, &h );
7494 if ( (w > 512) || (h > 512) ) {
7495 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7497 model_needs_splitting++;
7500 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7504 if ( model_needs_splitting ) {
7505 Num_models_needing_splitting++;
7507 eye_orient = model_orient = vmd_identity_matrix;
7508 eye_pos = model_pos = vmd_zero_vector;
7510 eye_pos.xyz.z = -pm->rad*2.0f;
7512 vector eye_to_model;
7514 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7515 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7517 fix t1 = timer_get_fixed_seconds();
7520 ta.p = ta.b = ta.h = 0.0f;
7525 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7527 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7529 modelstats_num_polys = modelstats_num_verts = 0;
7531 while( ta.h < PI2 ) {
7534 vm_angles_2_matrix(&m1, &ta );
7535 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7542 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7544 model_clear_instance( modelnum );
7545 model_set_detail_level(0); // use highest detail level
7546 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7554 int k = key_inkey();
7555 if ( k == KEY_ESC ) {
7560 fix t2 = timer_get_fixed_seconds();
7562 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7563 //bitmaps_used_this_frame /= framecount;
7565 modelstats_num_polys /= framecount;
7566 modelstats_num_verts /= framecount;
7568 Tmap_npixels /=framecount;
7571 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7572 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 );
7573 // 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 );
7579 int Time_models = 0;
7580 DCF_BOOL( time_models, Time_models );
7582 void Do_model_timings_test()
7586 if ( !Time_models ) return;
7588 mprintf(( "Timing models!\n" ));
7592 ubyte model_used[MAX_POLYGON_MODELS];
7593 int model_id[MAX_POLYGON_MODELS];
7594 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7599 for (i=0; i<Num_ship_types; i++ ) {
7600 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7602 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7603 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7606 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7607 if ( !Texture_fp ) return;
7609 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7610 if ( !Time_fp ) return;
7612 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7613 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7615 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7616 if ( model_used[i] ) {
7617 Time_model( model_id[i] );
7621 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7622 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7631 // Call this function when you want to inform the player that a feature is not
7632 // enabled in the DEMO version of FreSpace
7633 void game_feature_not_in_demo_popup()
7635 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7638 // format the specified time (fixed point) into a nice string
7639 void game_format_time(fix m_time,char *time_str)
7642 int hours,minutes,seconds;
7645 mtime = f2fl(m_time);
7647 // get the hours, minutes and seconds
7648 hours = (int)(mtime / 3600.0f);
7650 mtime -= (3600.0f * (float)hours);
7652 seconds = (int)mtime%60;
7653 minutes = (int)mtime/60;
7655 // print the hour if necessary
7657 sprintf(time_str,XSTR( "%d:", 201),hours);
7658 // if there are less than 10 minutes, print a leading 0
7660 strcpy(tmp,NOX("0"));
7661 strcat(time_str,tmp);
7665 // print the minutes
7667 sprintf(tmp,XSTR( "%d:", 201),minutes);
7668 strcat(time_str,tmp);
7670 sprintf(time_str,XSTR( "%d:", 201),minutes);
7673 // print the seconds
7675 strcpy(tmp,NOX("0"));
7676 strcat(time_str,tmp);
7678 sprintf(tmp,"%d",seconds);
7679 strcat(time_str,tmp);
7682 // Stuff version string in *str.
7683 void get_version_string(char *str)
7686 if ( FS_VERSION_BUILD == 0 ) {
7687 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7689 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7692 #if defined (FS2_DEMO)
7694 #elif defined (OEM_BUILD)
7695 strcat(str, " (OEM)");
7701 char myname[_MAX_PATH];
7702 int namelen, major, minor, build, waste;
7703 unsigned int buf_size;
7709 // Find my EXE file name
7710 hMod = GetModuleHandle(NULL);
7711 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7713 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7714 infop = (char *)malloc(version_size);
7715 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7717 // get the product version
7718 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7719 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7721 sprintf(str,"Dv%d.%02d",major, minor);
7723 sprintf(str,"v%d.%02d",major, minor);
7728 void get_version_string_short(char *str)
7730 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7733 // ----------------------------------------------------------------
7735 // OEM UPSELL SCREENS BEGIN
7737 // ----------------------------------------------------------------
7738 #if defined(OEM_BUILD)
7740 #define NUM_OEM_UPSELL_SCREENS 3
7741 #define OEM_UPSELL_SCREEN_DELAY 10000
7743 static int Oem_upsell_bitmaps_loaded = 0;
7744 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7745 static int Oem_upsell_screen_number = 0;
7746 static int Oem_upsell_show_next_bitmap_time;
7749 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7762 static int Oem_normal_cursor = -1;
7763 static int Oem_web_cursor = -1;
7764 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7765 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7767 void oem_upsell_next_screen()
7769 Oem_upsell_screen_number++;
7770 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7771 // extra long delay, mouse shown on last upsell
7772 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7776 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7780 void oem_upsell_load_bitmaps()
7784 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7785 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7789 void oem_upsell_unload_bitmaps()
7793 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7794 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7795 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7800 Oem_upsell_bitmaps_loaded = 0;
7803 // clickable hotspot on 3rd OEM upsell screen
7804 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7806 28, 350, 287, 96 // x, y, w, h
7809 45, 561, 460, 152 // x, y, w, h
7813 void oem_upsell_show_screens()
7815 int current_time, k;
7818 if ( !Oem_upsell_bitmaps_loaded ) {
7819 oem_upsell_load_bitmaps();
7820 Oem_upsell_bitmaps_loaded = 1;
7823 // may use upsell screens more than once
7824 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7825 Oem_upsell_screen_number = 0;
7831 int nframes; // used to pass, not really needed (should be 1)
7832 Oem_normal_cursor = gr_get_cursor_bitmap();
7833 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7834 Assert(Oem_web_cursor >= 0);
7835 if (Oem_web_cursor < 0) {
7836 Oem_web_cursor = Oem_normal_cursor;
7841 //oem_reset_trailer_timer();
7843 current_time = timer_get_milliseconds();
7848 // advance screen on keypress or timeout
7849 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7850 oem_upsell_next_screen();
7853 // check if we are done
7854 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7855 Oem_upsell_screen_number--;
7858 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7863 // show me the upsell
7864 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7865 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7869 // if this is the 3rd upsell, make it clickable, d00d
7870 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7872 int button_state = mouse_get_pos(&mx, &my);
7873 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])
7874 && (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]) )
7877 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7880 if (button_state & MOUSE_LEFT_BUTTON) {
7882 multi_pxo_url(OEM_UPSELL_URL);
7886 // switch cursor back to normal one
7887 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7892 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7902 oem_upsell_unload_bitmaps();
7904 // switch cursor back to normal one
7905 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7909 #endif // defined(OEM_BUILD)
7910 // ----------------------------------------------------------------
7912 // OEM UPSELL SCREENS END
7914 // ----------------------------------------------------------------
7918 // ----------------------------------------------------------------
7920 // DEMO UPSELL SCREENS BEGIN
7922 // ----------------------------------------------------------------
7926 //#define NUM_DEMO_UPSELL_SCREENS 4
7928 #define NUM_DEMO_UPSELL_SCREENS 2
7929 #define DEMO_UPSELL_SCREEN_DELAY 3000
7931 static int Demo_upsell_bitmaps_loaded = 0;
7932 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7933 static int Demo_upsell_screen_number = 0;
7934 static int Demo_upsell_show_next_bitmap_time;
7937 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7950 void demo_upsell_next_screen()
7952 Demo_upsell_screen_number++;
7953 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7954 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7956 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7960 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7961 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7962 #ifndef HARDWARE_ONLY
7963 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7970 void demo_upsell_load_bitmaps()
7974 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7975 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7979 void demo_upsell_unload_bitmaps()
7983 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7984 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7985 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7990 Demo_upsell_bitmaps_loaded = 0;
7993 void demo_upsell_show_screens()
7995 int current_time, k;
7998 if ( !Demo_upsell_bitmaps_loaded ) {
7999 demo_upsell_load_bitmaps();
8000 Demo_upsell_bitmaps_loaded = 1;
8003 // may use upsell screens more than once
8004 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8005 Demo_upsell_screen_number = 0;
8012 demo_reset_trailer_timer();
8014 current_time = timer_get_milliseconds();
8021 // don't time out, wait for keypress
8023 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8024 demo_upsell_next_screen();
8029 demo_upsell_next_screen();
8032 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8033 Demo_upsell_screen_number--;
8036 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8041 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8042 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8047 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8057 demo_upsell_unload_bitmaps();
8062 // ----------------------------------------------------------------
8064 // DEMO UPSELL SCREENS END
8066 // ----------------------------------------------------------------
8069 // ----------------------------------------------------------------
8071 // Subspace Ambient Sound START
8073 // ----------------------------------------------------------------
8075 static int Subspace_ambient_left_channel = -1;
8076 static int Subspace_ambient_right_channel = -1;
8079 void game_start_subspace_ambient_sound()
8081 if ( Subspace_ambient_left_channel < 0 ) {
8082 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8085 if ( Subspace_ambient_right_channel < 0 ) {
8086 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8090 void game_stop_subspace_ambient_sound()
8092 if ( Subspace_ambient_left_channel >= 0 ) {
8093 snd_stop(Subspace_ambient_left_channel);
8094 Subspace_ambient_left_channel = -1;
8097 if ( Subspace_ambient_right_channel >= 0 ) {
8098 snd_stop(Subspace_ambient_right_channel);
8099 Subspace_ambient_right_channel = -1;
8103 // ----------------------------------------------------------------
8105 // Subspace Ambient Sound END
8107 // ----------------------------------------------------------------
8109 // ----------------------------------------------------------------
8111 // CDROM detection code START
8113 // ----------------------------------------------------------------
8115 #define CD_SIZE_72_MINUTE_MAX (697000000)
8117 uint game_get_cd_used_space(char *path)
8121 char use_path[512] = "";
8122 char sub_path[512] = "";
8123 WIN32_FIND_DATA find;
8126 // recurse through all files and directories
8127 strcpy(use_path, path);
8128 strcat(use_path, "*.*");
8129 find_handle = FindFirstFile(use_path, &find);
8132 if(find_handle == INVALID_HANDLE_VALUE){
8138 // subdirectory. make sure to ignore . and ..
8139 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8141 strcpy(sub_path, path);
8142 strcat(sub_path, find.cFileName);
8143 strcat(sub_path, "\\");
8144 total += game_get_cd_used_space(sub_path);
8146 total += (uint)find.nFileSizeLow;
8148 } while(FindNextFile(find_handle, &find));
8151 FindClose(find_handle);
8163 // if volume_name is non-null, the CD name must match that
8164 int find_freespace_cd(char *volume_name)
8167 char oldpath[MAX_PATH];
8171 int volume_match = 0;
8175 GetCurrentDirectory(MAX_PATH, oldpath);
8177 for (i = 0; i < 26; i++)
8183 path[0] = (char)('A'+i);
8184 if (GetDriveType(path) == DRIVE_CDROM) {
8186 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8187 nprintf(("CD", "CD volume: %s\n", volume));
8189 // check for any CD volume
8190 int volume1_present = 0;
8191 int volume2_present = 0;
8192 int volume3_present = 0;
8194 char full_check[512] = "";
8196 // look for setup.exe
8197 strcpy(full_check, path);
8198 strcat(full_check, "setup.exe");
8199 find_handle = _findfirst(full_check, &find);
8200 if(find_handle != -1){
8201 volume1_present = 1;
8202 _findclose(find_handle);
8205 // look for intro.mve
8206 strcpy(full_check, path);
8207 strcat(full_check, "intro.mve");
8208 find_handle = _findfirst(full_check, &find);
8209 if(find_handle != -1){
8210 volume2_present = 1;
8211 _findclose(find_handle);
8214 // look for endpart1.mve
8215 strcpy(full_check, path);
8216 strcat(full_check, "endpart1.mve");
8217 find_handle = _findfirst(full_check, &find);
8218 if(find_handle != -1){
8219 volume3_present = 1;
8220 _findclose(find_handle);
8223 // see if we have the specific CD we're looking for
8224 if ( volume_name ) {
8226 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8230 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8234 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8238 if ( volume1_present || volume2_present || volume3_present ) {
8243 // 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
8244 if ( volume_match ){
8246 // 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
8247 if(volume2_present || volume3_present) {
8248 // first step - check to make sure its a cdrom
8249 if(GetDriveType(path) != DRIVE_CDROM){
8253 #if !defined(OEM_BUILD)
8254 // oem not on 80 min cds, so dont check tha size
8256 uint used_space = game_get_cd_used_space(path);
8257 if(used_space < CD_SIZE_72_MINUTE_MAX){
8260 #endif // !defined(OEM_BUILD)
8268 #endif // RELEASE_REAL
8274 SetCurrentDirectory(oldpath);
8283 int set_cdrom_path(int drive_num)
8287 if (drive_num < 0) { //no CD
8289 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8292 strcpy(Game_CDROM_dir,""); //set directory
8296 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8312 i = find_freespace_cd();
8314 rval = set_cdrom_path(i);
8318 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8320 nprintf(("CD", "FreeSpace CD not found\n"));
8328 int Last_cd_label_found = 0;
8329 char Last_cd_label[256];
8331 int game_cd_changed()
8338 if ( strlen(Game_CDROM_dir) == 0 ) {
8342 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8344 if ( found != Last_cd_label_found ) {
8345 Last_cd_label_found = found;
8347 mprintf(( "CD '%s' was inserted\n", label ));
8350 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8354 if ( Last_cd_label_found ) {
8355 if ( !stricmp( Last_cd_label, label )) {
8356 //mprintf(( "CD didn't change\n" ));
8358 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8362 // none found before, none found now.
8363 //mprintf(( "still no CD...\n" ));
8367 Last_cd_label_found = found;
8369 strcpy( Last_cd_label, label );
8371 strcpy( Last_cd_label, "" );
8382 // check if _any_ FreeSpace2 CDs are in the drive
8383 // return: 1 => CD now in drive
8384 // 0 => Could not find CD, they refuse to put it in the drive
8385 int game_do_cd_check(char *volume_name)
8387 #if !defined(GAME_CD_CHECK)
8393 int num_attempts = 0;
8394 int refresh_files = 0;
8396 int path_set_ok, popup_rval;
8398 cd_drive_num = find_freespace_cd(volume_name);
8399 path_set_ok = set_cdrom_path(cd_drive_num);
8400 if ( path_set_ok ) {
8402 if ( refresh_files ) {
8414 // no CD found, so prompt user
8415 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8417 if ( popup_rval != 1 ) {
8422 if ( num_attempts++ > 5 ) {
8433 // check if _any_ FreeSpace2 CDs are in the drive
8434 // return: 1 => CD now in drive
8435 // 0 => Could not find CD, they refuse to put it in the drive
8436 int game_do_cd_check_specific(char *volume_name, int cdnum)
8441 int num_attempts = 0;
8442 int refresh_files = 0;
8444 int path_set_ok, popup_rval;
8446 cd_drive_num = find_freespace_cd(volume_name);
8447 path_set_ok = set_cdrom_path(cd_drive_num);
8448 if ( path_set_ok ) {
8450 if ( refresh_files ) {
8461 // no CD found, so prompt user
8462 #if defined(DVD_MESSAGE_HACK)
8463 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8465 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8468 if ( popup_rval != 1 ) {
8473 if ( num_attempts++ > 5 ) {
8483 // only need to do this in RELEASE_REAL
8484 int game_do_cd_mission_check(char *filename)
8490 fs_builtin_mission *m = game_find_builtin_mission(filename);
8492 // check for changed CD
8493 if(game_cd_changed()){
8498 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8502 // not builtin, so do a general check (any FS2 CD will do)
8504 return game_do_cd_check();
8507 // does not have any CD requirement, do a general check
8508 if(strlen(m->cd_volume) <= 0){
8509 return game_do_cd_check();
8513 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8515 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8517 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8520 return game_do_cd_check();
8523 // did we find the cd?
8524 if(find_freespace_cd(m->cd_volume) >= 0){
8528 // make sure the volume exists
8529 int num_attempts = 0;
8530 int refresh_files = 0;
8532 int path_set_ok, popup_rval;
8534 cd_drive_num = find_freespace_cd(m->cd_volume);
8535 path_set_ok = set_cdrom_path(cd_drive_num);
8536 if ( path_set_ok ) {
8538 if ( refresh_files ) {
8545 // no CD found, so prompt user
8546 #if defined(DVD_MESSAGE_HACK)
8547 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8549 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8553 if ( popup_rval != 1 ) {
8558 if ( num_attempts++ > 5 ) {
8570 // ----------------------------------------------------------------
8572 // CDROM detection code END
8574 // ----------------------------------------------------------------
8576 // ----------------------------------------------------------------
8577 // SHIPS TBL VERIFICATION STUFF
8580 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8581 #define NUM_SHIPS_TBL_CHECKSUMS 1
8584 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8585 1696074201, // FS2 demo
8589 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8590 -463907578, // US - beta 1
8591 1696074201, // FS2 demo
8594 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8595 // -1022810006, // 1.0 FULL
8596 -1254285366 // 1.2 FULL (German)
8600 void verify_ships_tbl()
8604 Game_ships_tbl_valid = 1;
8610 // detect if the packfile exists
8611 CFILE *detect = cfopen("ships.tbl", "rb");
8612 Game_ships_tbl_valid = 0;
8616 Game_ships_tbl_valid = 0;
8620 // get the long checksum of the file
8622 cfseek(detect, 0, SEEK_SET);
8623 cf_chksum_long(detect, &file_checksum);
8627 // now compare the checksum/filesize against known #'s
8628 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8629 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8630 Game_ships_tbl_valid = 1;
8637 DCF(shipspew, "display the checksum for the current ships.tbl")
8640 CFILE *detect = cfopen("ships.tbl", "rb");
8641 // get the long checksum of the file
8643 cfseek(detect, 0, SEEK_SET);
8644 cf_chksum_long(detect, &file_checksum);
8647 dc_printf("%d", file_checksum);
8650 // ----------------------------------------------------------------
8651 // WEAPONS TBL VERIFICATION STUFF
8654 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8655 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8658 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8659 -266420030, // demo 1
8663 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8664 141718090, // US - beta 1
8665 -266420030, // demo 1
8668 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8669 // 399297860, // 1.0 FULL
8670 -553984927 // 1.2 FULL (german)
8674 void verify_weapons_tbl()
8678 Game_weapons_tbl_valid = 1;
8684 // detect if the packfile exists
8685 CFILE *detect = cfopen("weapons.tbl", "rb");
8686 Game_weapons_tbl_valid = 0;
8690 Game_weapons_tbl_valid = 0;
8694 // get the long checksum of the file
8696 cfseek(detect, 0, SEEK_SET);
8697 cf_chksum_long(detect, &file_checksum);
8701 // now compare the checksum/filesize against known #'s
8702 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8703 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8704 Game_weapons_tbl_valid = 1;
8711 DCF(wepspew, "display the checksum for the current weapons.tbl")
8714 CFILE *detect = cfopen("weapons.tbl", "rb");
8715 // get the long checksum of the file
8717 cfseek(detect, 0, SEEK_SET);
8718 cf_chksum_long(detect, &file_checksum);
8721 dc_printf("%d", file_checksum);
8724 // if the game is running using hacked data
8725 int game_hacked_data()
8728 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8736 void display_title_screen()
8738 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8739 ///int title_bitmap;
8742 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8743 if (title_bitmap == -1) {
8749 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8750 extern void d3d_start_frame();
8756 gr_set_bitmap(title_bitmap);
8763 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8764 extern void d3d_stop_frame();
8772 bm_unload(title_bitmap);
8773 #endif // FS2_DEMO || OEM_BUILD
8776 // return true if the game is running with "low memory", which is less than 48MB
8777 bool game_using_low_mem()
8779 if (Use_low_mem == 0) {