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.21 2002/07/28 05:05:08 relnev
19 * removed some old stuff
21 * Revision 1.20 2002/07/24 00:20:41 relnev
24 * Revision 1.19 2002/06/17 06:33:08 relnev
25 * ryan's struct patch for gcc 2.95
27 * Revision 1.18 2002/06/16 04:46:33 relnev
28 * set up correct checksums for demo
30 * Revision 1.17 2002/06/09 04:41:17 relnev
31 * added copyright header
33 * Revision 1.16 2002/06/09 03:16:04 relnev
36 * removed unneeded asm, old sdl 2d setup.
38 * fixed crash caused by opengl_get_region.
40 * Revision 1.15 2002/06/05 08:05:28 relnev
41 * stub/warning removal.
43 * reworked the sound code.
45 * Revision 1.14 2002/06/05 04:03:32 relnev
46 * finished cfilesystem.
48 * removed some old code.
50 * fixed mouse save off-by-one.
54 * Revision 1.13 2002/06/02 04:26:34 relnev
57 * Revision 1.12 2002/06/02 00:31:35 relnev
58 * implemented osregistry
60 * Revision 1.11 2002/06/01 09:00:34 relnev
61 * silly debug memmanager
63 * Revision 1.10 2002/06/01 07:12:32 relnev
64 * a few NDEBUG updates.
66 * removed a few warnings.
68 * Revision 1.9 2002/05/31 03:05:59 relnev
71 * Revision 1.8 2002/05/29 02:52:32 theoddone33
72 * Enable OpenGL renderer
74 * Revision 1.7 2002/05/28 08:52:03 relnev
75 * implemented two assembly stubs.
77 * cleaned up a few warnings.
79 * added a little demo hackery to make it progress a little farther.
81 * Revision 1.6 2002/05/28 06:28:20 theoddone33
82 * Filesystem mods, actually reads some data files now
84 * Revision 1.5 2002/05/28 04:07:28 theoddone33
85 * New graphics stubbing arrangement
87 * Revision 1.4 2002/05/27 22:46:52 theoddone33
88 * Remove more undefined symbols
90 * Revision 1.3 2002/05/26 23:31:18 relnev
91 * added a few files that needed to be compiled
93 * freespace.cpp: now compiles
95 * Revision 1.2 2002/05/07 03:16:44 theoddone33
96 * The Great Newline Fix
98 * Revision 1.1.1.1 2002/05/03 03:28:09 root
102 * 201 6/16/00 3:15p Jefff
103 * sim of the year dvd version changes, a few german soty localization
106 * 200 11/03/99 11:06a Jefff
109 * 199 10/26/99 5:07p Jamest
110 * fixed jeffs dumb debug code
112 * 198 10/25/99 5:53p Jefff
113 * call control_config_common_init() on startup
115 * 197 10/14/99 10:18a Daveb
116 * Fixed incorrect CD checking problem on standalone server.
118 * 196 10/13/99 9:22a Daveb
119 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
120 * related to movies. Fixed launcher spawning from PXO screen.
122 * 195 10/06/99 11:05a Jefff
123 * new oem upsell 3 hotspot coords
125 * 194 10/06/99 10:31a Jefff
128 * 193 10/01/99 9:10a Daveb
131 * 192 9/15/99 4:57a Dave
132 * Updated ships.tbl checksum
134 * 191 9/15/99 3:58a Dave
135 * Removed framerate warning at all times.
137 * 190 9/15/99 3:16a Dave
138 * Remove mt-011.fs2 from the builtin mission list.
140 * 189 9/15/99 1:45a Dave
141 * Don't init joystick on standalone. Fixed campaign mode on standalone.
142 * Fixed no-score-report problem in TvT
144 * 188 9/14/99 6:08a Dave
145 * Updated (final) single, multi, and campaign list.
147 * 187 9/14/99 3:26a Dave
148 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
149 * respawn-too-early problem. Made a few crash points safe.
151 * 186 9/13/99 4:52p Dave
154 * 185 9/12/99 8:09p Dave
155 * Fixed problem where skip-training button would cause mission messages
156 * not to get paged out for the current mission.
158 * 184 9/10/99 11:53a Dave
159 * Shutdown graphics before sound to eliminate apparent lockups when
160 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
162 * 183 9/09/99 11:40p Dave
163 * Handle an Assert() in beam code. Added supernova sounds. Play the right
164 * 2 end movies properly, based upon what the player did in the mission.
166 * 182 9/08/99 10:29p Dave
167 * Make beam sound pausing and unpausing much safer.
169 * 181 9/08/99 10:01p Dave
170 * Make sure game won't run in a drive's root directory. Make sure
171 * standalone routes suqad war messages properly to the host.
173 * 180 9/08/99 3:22p Dave
174 * Updated builtin mission list.
176 * 179 9/08/99 12:01p Jefff
177 * fixed Game_builtin_mission_list typo on Training-2.fs2
179 * 178 9/08/99 9:48a Andsager
180 * Add force feedback for engine wash.
182 * 177 9/07/99 4:01p Dave
183 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
184 * does everything properly (setting up address when binding). Remove
185 * black rectangle background from UI_INPUTBOX.
187 * 176 9/13/99 2:40a Dave
188 * Comment in full 80 minute CD check for RELEASE_REAL builds.
190 * 175 9/06/99 6:38p Dave
191 * Improved CD detection code.
193 * 174 9/06/99 1:30a Dave
194 * Intermediate checkin. Started on enforcing CD-in-drive to play the
197 * 173 9/06/99 1:16a Dave
198 * Make sure the user sees the intro movie.
200 * 172 9/04/99 8:00p Dave
201 * Fixed up 1024 and 32 bit movie support.
203 * 171 9/03/99 1:32a Dave
204 * CD checking by act. Added support to play 2 cutscenes in a row
205 * seamlessly. Fixed super low level cfile bug related to files in the
206 * root directory of a CD. Added cheat code to set campaign mission # in
209 * 170 9/01/99 10:49p Dave
210 * Added nice SquadWar checkbox to the client join wait screen.
212 * 169 9/01/99 10:14a Dave
215 * 168 8/29/99 4:51p Dave
216 * Fixed damaged checkin.
218 * 167 8/29/99 4:18p Andsager
219 * New "burst" limit for friendly damage. Also credit more damage done
220 * against large friendly ships.
222 * 166 8/27/99 6:38p Alanl
223 * crush the blasted repeating messages bug
225 * 164 8/26/99 9:09p Dave
226 * Force framerate check in everything but a RELEASE_REAL build.
228 * 163 8/26/99 9:45a Dave
229 * First pass at easter eggs and cheats.
231 * 162 8/24/99 8:55p Dave
232 * Make sure nondimming pixels work properly in tech menu.
234 * 161 8/24/99 1:49a Dave
235 * Fixed client-side afterburner stuttering. Added checkbox for no version
236 * checking on PXO join. Made button info passing more friendly between
239 * 160 8/22/99 5:53p Dave
240 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
241 * instead of ship designations for multiplayer players.
243 * 159 8/22/99 1:19p Dave
244 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
245 * which d3d cards are detected.
247 * 158 8/20/99 2:09p Dave
248 * PXO banner cycling.
250 * 157 8/19/99 10:59a Dave
251 * Packet loss detection.
253 * 156 8/19/99 10:12a Alanl
254 * preload mission-specific messages on machines greater than 48MB
256 * 155 8/16/99 4:04p Dave
257 * Big honking checkin.
259 * 154 8/11/99 5:54p Dave
260 * Fixed collision problem. Fixed standalone ghost problem.
262 * 153 8/10/99 7:59p Jefff
265 * 152 8/10/99 6:54p Dave
266 * Mad optimizations. Added paging to the nebula effect.
268 * 151 8/10/99 3:44p Jefff
269 * loads Intelligence information on startup
271 * 150 8/09/99 3:47p Dave
272 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
273 * non-nebula missions.
275 * 149 8/09/99 2:21p Andsager
276 * Fix patching from multiplayer direct to launcher update tab.
278 * 148 8/09/99 10:36a Dave
279 * Version info for game.
281 * 147 8/06/99 9:46p Dave
282 * Hopefully final changes for the demo.
284 * 146 8/06/99 3:34p Andsager
285 * Make title version info "(D)" -> "D" show up nicely
287 * 145 8/06/99 2:59p Adamp
288 * Fixed NT launcher/update problem.
290 * 144 8/06/99 1:52p Dave
291 * Bumped up MAX_BITMAPS for the demo.
293 * 143 8/06/99 12:17p Andsager
294 * Demo: down to just 1 demo dog
296 * 142 8/05/99 9:39p Dave
297 * Yet another new checksum.
299 * 141 8/05/99 6:19p Dave
300 * New demo checksums.
302 * 140 8/05/99 5:31p Andsager
303 * Up demo version 1.01
305 * 139 8/05/99 4:22p Andsager
306 * No time limit on upsell screens. Reverse order of display of upsell
309 * 138 8/05/99 4:17p Dave
310 * Tweaks to client interpolation.
312 * 137 8/05/99 3:52p Danw
314 * 136 8/05/99 3:01p Danw
316 * 135 8/05/99 2:43a Anoop
317 * removed duplicate definition.
319 * 134 8/05/99 2:13a Dave
322 * 133 8/05/99 2:05a Dave
325 * 132 8/05/99 1:22a Andsager
328 * 131 8/04/99 9:51p Andsager
329 * Add title screen to demo
331 * 130 8/04/99 6:47p Jefff
332 * fixed link error resulting from #ifdefs
334 * 129 8/04/99 6:26p Dave
335 * Updated ship tbl checksum.
337 * 128 8/04/99 5:40p Andsager
338 * Add multiple demo dogs
340 * 127 8/04/99 5:36p Andsager
341 * Show upsell screens at end of demo campaign before returning to main
344 * 126 8/04/99 11:42a Danw
345 * tone down EAX reverb
347 * 125 8/04/99 11:23a Dave
348 * Updated demo checksums.
350 * 124 8/03/99 11:02p Dave
351 * Maybe fixed sync problems in multiplayer.
353 * 123 8/03/99 6:21p Jefff
356 * 122 8/03/99 3:44p Andsager
357 * Launch laucher if trying to run FS without first having configured
360 * 121 8/03/99 12:45p Dave
363 * 120 8/02/99 9:13p Dave
366 * 119 7/30/99 10:31p Dave
367 * Added comm menu to the configurable hud files.
369 * 118 7/30/99 5:17p Andsager
370 * first fs2demo checksums
372 * 117 7/29/99 3:09p Anoop
374 * 116 7/29/99 12:05a Dave
375 * Nebula speed optimizations.
377 * 115 7/27/99 8:59a Andsager
378 * Make major, minor version consistent for all builds. Only show major
379 * and minor for launcher update window.
381 * 114 7/26/99 5:50p Dave
382 * Revised ingame join. Better? We'll see....
384 * 113 7/26/99 5:27p Andsager
385 * Add training mission as builtin to demo build
387 * 112 7/24/99 1:54p Dave
388 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
391 * 111 7/22/99 4:00p Dave
392 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
394 * 110 7/21/99 8:10p Dave
395 * First run of supernova effect.
397 * 109 7/20/99 1:49p Dave
398 * Peter Drake build. Fixed some release build warnings.
400 * 108 7/19/99 2:26p Andsager
401 * set demo multiplayer missions
403 * 107 7/18/99 5:19p Dave
404 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
406 * 106 7/16/99 1:50p Dave
407 * 8 bit aabitmaps. yay.
409 * 105 7/15/99 3:07p Dave
410 * 32 bit detection support. Mouse coord commandline.
412 * 104 7/15/99 2:13p Dave
413 * Added 32 bit detection.
415 * 103 7/15/99 9:20a Andsager
416 * FS2_DEMO initial checkin
418 * 102 7/14/99 11:02a Dave
419 * Skill level default back to easy. Blech.
421 * 101 7/09/99 5:54p Dave
422 * Seperated cruiser types into individual types. Added tons of new
423 * briefing icons. Campaign screen.
425 * 100 7/08/99 4:43p Andsager
426 * New check for sparky_hi and print if not found.
428 * 99 7/08/99 10:53a Dave
429 * New multiplayer interpolation scheme. Not 100% done yet, but still
430 * better than the old way.
432 * 98 7/06/99 4:24p Dave
433 * Mid-level checkin. Starting on some potentially cool multiplayer
436 * 97 7/06/99 3:35p Andsager
437 * Allow movie to play before red alert mission.
439 * 96 7/03/99 5:50p Dave
440 * Make rotated bitmaps draw properly in padlock views.
442 * 95 7/02/99 9:55p Dave
443 * Player engine wash sound.
445 * 94 7/02/99 4:30p Dave
446 * Much more sophisticated lightning support.
448 * 93 6/29/99 7:52p Dave
449 * Put in exception handling in FS2.
451 * 92 6/22/99 9:37p Dave
452 * Put in pof spewing.
454 * 91 6/16/99 4:06p Dave
455 * New pilot info popup. Added new draw-bitmap-as-poly function.
457 * 90 6/15/99 1:56p Andsager
458 * For release builds, allow start up in high res only with
461 * 89 6/15/99 9:34a Dave
462 * Fixed key checking in single threaded version of the stamp notification
465 * 88 6/09/99 2:55p Andsager
466 * Allow multiple asteroid subtypes (of large, medium, small) and follow
469 * 87 6/08/99 1:14a Dave
470 * Multi colored hud test.
472 * 86 6/04/99 9:52a Dave
473 * Fixed some rendering problems.
475 * 85 6/03/99 10:15p Dave
476 * Put in temporary main hall screen.
478 * 84 6/02/99 6:18p Dave
479 * Fixed TNT lockup problems! Wheeeee!
481 * 83 6/01/99 3:52p Dave
482 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
483 * dead popup, pxo find player popup, pxo private room popup.
485 * 82 5/26/99 1:28p Jasenw
486 * changed coords for loading ani
488 * 81 5/26/99 11:46a Dave
489 * Added ship-blasting lighting and made the randomization of lighting
490 * much more customizable.
492 * 80 5/24/99 5:45p Dave
493 * Added detail levels to the nebula, with a decent speedup. Split nebula
494 * lightning into its own section.
512 #include "systemvars.h"
517 #include "starfield.h"
518 #include "lighting.h"
523 #include "fireballs.h"
527 #include "floating.h"
528 #include "gamesequence.h"
530 #include "optionsmenu.h"
531 #include "playermenu.h"
532 #include "trainingmenu.h"
533 #include "techmenu.h"
536 #include "hudmessage.h"
538 #include "missiongoals.h"
539 #include "missionparse.h"
544 #include "multiutil.h"
545 #include "multimsgs.h"
549 #include "freespace.h"
550 #include "managepilot.h"
552 #include "contexthelp.h"
555 #include "missionbrief.h"
556 #include "missiondebrief.h"
558 #include "missionshipchoice.h"
560 #include "hudconfig.h"
561 #include "controlsconfig.h"
562 #include "missionmessage.h"
563 #include "missiontraining.h"
565 #include "hudtarget.h"
567 #include "eventmusic.h"
568 #include "animplay.h"
569 #include "missionweaponchoice.h"
570 #include "missionlog.h"
571 #include "audiostr.h"
573 #include "missioncampaign.h"
575 #include "missionhotkey.h"
576 #include "objectsnd.h"
577 #include "cmeasure.h"
579 #include "linklist.h"
580 #include "shockwave.h"
581 #include "afterburner.h"
586 #include "stand_gui.h"
587 #include "pcxutils.h"
588 #include "hudtargetbox.h"
589 #include "multi_xfer.h"
590 #include "hudescort.h"
591 #include "multiutil.h"
594 #include "multiteamselect.h"
597 #include "readyroom.h"
598 #include "mainhallmenu.h"
599 #include "multilag.h"
601 #include "particle.h"
603 #include "multi_ingame.h"
604 #include "snazzyui.h"
605 #include "asteroid.h"
606 #include "popupdead.h"
607 #include "multi_voice.h"
608 #include "missioncmdbrief.h"
609 #include "redalert.h"
610 #include "gameplayhelp.h"
611 #include "multilag.h"
612 #include "staticrand.h"
613 #include "multi_pmsg.h"
614 #include "levelpaging.h"
615 #include "observer.h"
616 #include "multi_pause.h"
617 #include "multi_endgame.h"
618 #include "cutscenes.h"
619 #include "multi_respawn.h"
621 #include "multi_obj.h"
622 #include "multi_log.h"
624 #include "localize.h"
625 #include "osregistry.h"
626 #include "barracks.h"
627 #include "missionpause.h"
629 #include "alphacolors.h"
630 #include "objcollide.h"
633 #include "neblightning.h"
634 #include "shipcontrails.h"
637 #include "multi_dogfight.h"
638 #include "multi_rate.h"
639 #include "muzzleflash.h"
643 #include "mainhalltemp.h"
644 #include "exceptionhandler.h"
648 #include "supernova.h"
649 #include "hudshield.h"
650 // #include "names.h"
652 #include "missionloopbrief.h"
656 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
662 // 1.00.04 5/26/98 MWA -- going final (12 pm)
663 // 1.00.03 5/26/98 MWA -- going final (3 am)
664 // 1.00.02 5/25/98 MWA -- going final
665 // 1.00.01 5/25/98 MWA -- going final
666 // 0.90 5/21/98 MWA -- getting ready for final.
667 // 0.10 4/9/98. Set by MK.
669 // Demo version: (obsolete since DEMO codebase split from tree)
670 // 0.03 4/10/98 AL. Interplay rev
671 // 0.02 4/8/98 MK. Increased when this system was modified.
672 // 0.01 4/7/98? AL. First release to Interplay QA.
675 // 1.00 5/28/98 AL. First release to Interplay QA.
677 void game_level_init(int seed = -1);
678 void game_post_level_init();
679 void game_do_frame();
680 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
681 void game_reset_time();
682 void game_show_framerate(); // draws framerate in lower right corner
684 int Game_no_clear = 0;
686 int Pofview_running = 0;
687 int Nebedit_running = 0;
689 typedef struct big_expl_flash {
690 float max_flash_intensity; // max intensity
691 float cur_flash_intensity; // cur intensity
692 int flash_start; // start time
695 #define FRAME_FILTER 16
697 #define DEFAULT_SKILL_LEVEL 1
698 int Game_skill_level = DEFAULT_SKILL_LEVEL;
700 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
701 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
703 #define EXE_FNAME ("fs2.exe")
704 #define LAUNCHER_FNAME ("freespace2.exe")
706 // JAS: Code for warphole camera.
707 // Needs to be cleaned up.
708 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
709 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
710 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
711 matrix Camera_orient = IDENTITY_MATRIX;
712 float Camera_damping = 1.0f;
713 float Camera_time = 0.0f;
714 float Warpout_time = 0.0f;
715 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
716 int Warpout_sound = -1;
718 int Use_joy_mouse = 0;
719 int Use_palette_flash = 1;
721 int Use_fullscreen_at_startup = 0;
723 int Show_area_effect = 0;
724 object *Last_view_target = NULL;
726 int dogfight_blown = 0;
729 float frametimes[FRAME_FILTER];
730 float frametotal = 0.0f;
734 int Show_framerate = 0;
736 int Show_framerate = 1;
739 int Framerate_cap = 120;
742 int Show_target_debug_info = 0;
743 int Show_target_weapons = 0;
747 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
750 int Debug_octant = -1;
752 fix Game_time_compression = F1_0;
754 // if the ships.tbl the player has is valid
755 int Game_ships_tbl_valid = 0;
757 // if the weapons.tbl the player has is valid
758 int Game_weapons_tbl_valid = 0;
762 extern int Player_attacking_enabled;
766 int Pre_player_entry;
768 int Fred_running = 0;
769 char Game_current_mission_filename[MAX_FILENAME_LEN];
770 int game_single_step = 0;
771 int last_single_step=0;
773 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
774 extern int MSG_WINDOW_Y_START;
775 extern int MSG_WINDOW_HEIGHT;
777 int game_zbuffer = 1;
778 //static int Game_music_paused;
779 static int Game_paused;
783 #define EXPIRE_BAD_CHECKSUM 1
784 #define EXPIRE_BAD_TIME 2
786 extern void ssm_init();
787 extern void ssm_level_init();
788 extern void ssm_process();
790 // static variable to contain the time this version was built
791 // commented out for now until
792 // I figure out how to get the username into the file
793 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
795 // defines and variables used for dumping frame for making trailers.
797 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
798 int Debug_dump_trigger = 0;
799 int Debug_dump_frame_count;
800 int Debug_dump_frame_num = 0;
801 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
804 // amount of time to wait after the player has died before we display the death died popup
805 #define PLAYER_DIED_POPUP_WAIT 2500
806 int Player_died_popup_wait = -1;
807 int Player_multi_died_check = -1;
809 // builtin mission list stuff
811 int Game_builtin_mission_count = 6;
812 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
813 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
814 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
815 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
816 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
817 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
818 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
820 #elif defined(PD_BUILD)
821 int Game_builtin_mission_count = 4;
822 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
823 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
824 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
825 { "sm1-01", (FSB_FROM_VOLITION), "" },
826 { "sm1-05", (FSB_FROM_VOLITION), "" },
828 #elif defined(MULTIPLAYER_BETA)
829 int Game_builtin_mission_count = 17;
830 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
832 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
833 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
834 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
835 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
838 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
841 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
845 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
846 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
847 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
848 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
850 #elif defined(OEM_BUILD)
851 int Game_builtin_mission_count = 17;
852 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
853 // oem version - act 1 only
854 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
857 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
858 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
859 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
860 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
861 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
862 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
863 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
866 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
869 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
870 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
871 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
872 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
875 int Game_builtin_mission_count = 92;
876 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
877 // single player campaign
878 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
881 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
882 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
883 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
884 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
885 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
886 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
887 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
896 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
899 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
902 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
903 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
904 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
905 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
906 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
907 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
908 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
909 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
911 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
922 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
925 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
927 // multiplayer missions
930 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
936 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
980 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
983 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
984 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
985 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
986 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
987 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
992 // Internal function prototypes
993 void game_maybe_draw_mouse(float frametime);
994 void init_animating_pointer();
995 void load_animating_pointer(char *filename, int dx, int dy);
996 void unload_animating_pointer();
997 void game_do_training_checks();
998 void game_shutdown(void);
999 void game_show_event_debug(float frametime);
1000 void game_event_debug_init();
1002 void demo_upsell_show_screens();
1003 void game_start_subspace_ambient_sound();
1004 void game_stop_subspace_ambient_sound();
1005 void verify_ships_tbl();
1006 void verify_weapons_tbl();
1007 void display_title_screen();
1009 // loading background filenames
1010 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1011 "LoadingBG", // GR_640
1012 "2_LoadingBG" // GR_1024
1016 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1017 "Loading.ani", // GR_640
1018 "2_Loading.ani" // GR_1024
1021 #if defined(FS2_DEMO)
1022 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1026 #elif defined(OEM_BUILD)
1027 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1034 char Game_CDROM_dir[MAX_PATH_LEN];
1037 // How much RAM is on this machine. Set in WinMain
1038 uint Freespace_total_ram = 0;
1041 float Game_flash_red = 0.0f;
1042 float Game_flash_green = 0.0f;
1043 float Game_flash_blue = 0.0f;
1044 float Sun_spot = 0.0f;
1045 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1047 // game shudder stuff (in ms)
1048 int Game_shudder_time = -1;
1049 int Game_shudder_total = 0;
1050 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1053 sound_env Game_sound_env;
1054 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1055 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1057 int Game_sound_env_update_timestamp;
1059 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1062 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1064 fs_builtin_mission *game_find_builtin_mission(char *filename)
1068 // look through all existing builtin missions
1069 for(idx=0; idx<Game_builtin_mission_count; idx++){
1070 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1071 return &Game_builtin_mission_list[idx];
1079 int game_get_default_skill_level()
1081 return DEFAULT_SKILL_LEVEL;
1085 void game_flash_reset()
1087 Game_flash_red = 0.0f;
1088 Game_flash_green = 0.0f;
1089 Game_flash_blue = 0.0f;
1091 Big_expl_flash.max_flash_intensity = 0.0f;
1092 Big_expl_flash.cur_flash_intensity = 0.0f;
1093 Big_expl_flash.flash_start = 0;
1096 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1097 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1099 void game_framerate_check_init()
1101 // zero critical time
1102 Gf_critical_time = 0.0f;
1105 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1106 // if this is a glide card
1107 if(gr_screen.mode == GR_GLIDE){
1109 extern GrHwConfiguration hwconfig;
1112 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1113 Gf_critical = 15.0f;
1117 Gf_critical = 10.0f;
1122 Gf_critical = 15.0f;
1125 // d3d. only care about good cards here I guess (TNT)
1127 Gf_critical = 15.0f;
1130 // if this is a glide card
1131 if(gr_screen.mode == GR_GLIDE){
1133 extern GrHwConfiguration hwconfig;
1136 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1137 Gf_critical = 25.0f;
1141 Gf_critical = 20.0f;
1146 Gf_critical = 25.0f;
1149 // d3d. only care about good cards here I guess (TNT)
1151 Gf_critical = 25.0f;
1156 extern float Framerate;
1157 void game_framerate_check()
1161 // if the current framerate is above the critical level, add frametime
1162 if(Framerate >= Gf_critical){
1163 Gf_critical_time += flFrametime;
1166 if(!Show_framerate){
1170 // display if we're above the critical framerate
1171 if(Framerate < Gf_critical){
1172 gr_set_color_fast(&Color_bright_red);
1173 gr_string(200, y_start, "Framerate warning");
1178 // display our current pct of good frametime
1179 if(f2fl(Missiontime) >= 0.0f){
1180 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1183 gr_set_color_fast(&Color_bright_green);
1185 gr_set_color_fast(&Color_bright_red);
1188 gr_printf(200, y_start, "%d%%", (int)pct);
1195 // Adds a flash effect. These can be positive or negative.
1196 // The range will get capped at around -1 to 1, so stick
1197 // with a range like that.
1198 void game_flash( float r, float g, float b )
1200 Game_flash_red += r;
1201 Game_flash_green += g;
1202 Game_flash_blue += b;
1204 if ( Game_flash_red < -1.0f ) {
1205 Game_flash_red = -1.0f;
1206 } else if ( Game_flash_red > 1.0f ) {
1207 Game_flash_red = 1.0f;
1210 if ( Game_flash_green < -1.0f ) {
1211 Game_flash_green = -1.0f;
1212 } else if ( Game_flash_green > 1.0f ) {
1213 Game_flash_green = 1.0f;
1216 if ( Game_flash_blue < -1.0f ) {
1217 Game_flash_blue = -1.0f;
1218 } else if ( Game_flash_blue > 1.0f ) {
1219 Game_flash_blue = 1.0f;
1224 // Adds a flash for Big Ship explosions
1225 // cap range from 0 to 1
1226 void big_explosion_flash(float flash)
1228 Big_expl_flash.flash_start = timestamp(1);
1232 } else if (flash < 0.0f) {
1236 Big_expl_flash.max_flash_intensity = flash;
1237 Big_expl_flash.cur_flash_intensity = 0.0f;
1240 // Amount to diminish palette towards normal, per second.
1241 #define DIMINISH_RATE 0.75f
1242 #define SUN_DIMINISH_RATE 6.00f
1246 float sn_glare_scale = 1.7f;
1249 dc_get_arg(ARG_FLOAT);
1250 sn_glare_scale = Dc_arg_float;
1253 float Supernova_last_glare = 0.0f;
1254 void game_sunspot_process(float frametime)
1258 float Sun_spot_goal = 0.0f;
1261 sn_stage = supernova_active();
1263 // sunspot differently based on supernova stage
1265 // approaching. player still in control
1268 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1271 light_get_global_dir(&light_dir, 0);
1273 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1276 // scale it some more
1277 dot = dot * (0.5f + (pct * 0.5f));
1280 Sun_spot_goal += (dot * sn_glare_scale);
1283 // draw the sun glow
1284 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1285 // draw the glow for this sun
1286 stars_draw_sun_glow(0);
1289 Supernova_last_glare = Sun_spot_goal;
1292 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1295 Sun_spot_goal = 0.9f;
1296 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1298 if(Sun_spot_goal > 1.0f){
1299 Sun_spot_goal = 1.0f;
1302 Sun_spot_goal *= sn_glare_scale;
1303 Supernova_last_glare = Sun_spot_goal;
1306 // fade to white. display dead popup
1309 Supernova_last_glare += (2.0f * flFrametime);
1310 if(Supernova_last_glare > 2.0f){
1311 Supernova_last_glare = 2.0f;
1314 Sun_spot_goal = Supernova_last_glare;
1321 // check sunspots for all suns
1322 n_lights = light_get_global_count();
1325 for(idx=0; idx<n_lights; idx++){
1326 //(vector *eye_pos, matrix *eye_orient)
1327 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1330 light_get_global_dir(&light_dir, idx);
1332 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1334 Sun_spot_goal += (float)pow(dot,85.0f);
1336 // draw the glow for this sun
1337 stars_draw_sun_glow(idx);
1339 Sun_spot_goal = 0.0f;
1345 Sun_spot_goal = 0.0f;
1349 float dec_amount = frametime*SUN_DIMINISH_RATE;
1351 if ( Sun_spot < Sun_spot_goal ) {
1352 Sun_spot += dec_amount;
1353 if ( Sun_spot > Sun_spot_goal ) {
1354 Sun_spot = Sun_spot_goal;
1356 } else if ( Sun_spot > Sun_spot_goal ) {
1357 Sun_spot -= dec_amount;
1358 if ( Sun_spot < Sun_spot_goal ) {
1359 Sun_spot = Sun_spot_goal;
1365 // Call once a frame to diminish the
1366 // flash effect to 0.
1367 void game_flash_diminish(float frametime)
1369 float dec_amount = frametime*DIMINISH_RATE;
1371 if ( Game_flash_red > 0.0f ) {
1372 Game_flash_red -= dec_amount;
1373 if ( Game_flash_red < 0.0f )
1374 Game_flash_red = 0.0f;
1376 Game_flash_red += dec_amount;
1377 if ( Game_flash_red > 0.0f )
1378 Game_flash_red = 0.0f;
1381 if ( Game_flash_green > 0.0f ) {
1382 Game_flash_green -= dec_amount;
1383 if ( Game_flash_green < 0.0f )
1384 Game_flash_green = 0.0f;
1386 Game_flash_green += dec_amount;
1387 if ( Game_flash_green > 0.0f )
1388 Game_flash_green = 0.0f;
1391 if ( Game_flash_blue > 0.0f ) {
1392 Game_flash_blue -= dec_amount;
1393 if ( Game_flash_blue < 0.0f )
1394 Game_flash_blue = 0.0f;
1396 Game_flash_blue += dec_amount;
1397 if ( Game_flash_blue > 0.0f )
1398 Game_flash_blue = 0.0f;
1401 // update big_explosion_cur_flash
1402 #define TIME_UP 1500
1403 #define TIME_DOWN 2500
1404 int duration = TIME_UP + TIME_DOWN;
1405 int time = timestamp_until(Big_expl_flash.flash_start);
1406 if (time > -duration) {
1408 if (time < TIME_UP) {
1409 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1412 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1416 if ( Use_palette_flash ) {
1418 // static int or=0, og=0, ob=0;
1420 // Change the 200 to change the color range of colors.
1421 r = fl2i( Game_flash_red*128.0f );
1422 g = fl2i( Game_flash_green*128.0f );
1423 b = fl2i( Game_flash_blue*128.0f );
1425 if ( Sun_spot > 0.0f ) {
1426 r += fl2i(Sun_spot*128.0f);
1427 g += fl2i(Sun_spot*128.0f);
1428 b += fl2i(Sun_spot*128.0f);
1431 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1432 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1433 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1434 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1437 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1438 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1439 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1441 if ( (r!=0) || (g!=0) || (b!=0) ) {
1442 gr_flash( r, g, b );
1444 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1455 void game_level_close()
1457 // De-Initialize the game subsystems
1458 message_mission_shutdown();
1459 event_music_level_close();
1460 game_stop_looped_sounds();
1462 obj_snd_level_close(); // uninit object-linked persistant sounds
1463 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1464 anim_level_close(); // stop and clean up any anim instances
1465 shockwave_level_close();
1466 fireball_level_close();
1468 mission_event_shutdown();
1469 asteroid_level_close();
1470 model_cache_reset(); // Reset/free all the model caching stuff
1471 flak_level_close(); // unload flak stuff
1472 neb2_level_close(); // shutdown gaseous nebula stuff
1475 mflash_level_close();
1477 audiostream_unpause_all();
1482 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1483 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1484 void game_level_init(int seed)
1486 // seed the random number generator
1488 // if no seed was passed, seed the generator either from the time value, or from the
1489 // netgame security flags -- ensures that all players in multiplayer game will have the
1490 // same randon number sequence (with static rand functions)
1491 if ( Game_mode & GM_NORMAL ) {
1492 Game_level_seed = time(NULL);
1494 Game_level_seed = Netgame.security;
1497 // mwa 9/17/98 -- maybe this assert isn't needed????
1498 Assert( !(Game_mode & GM_MULTIPLAYER) );
1499 Game_level_seed = seed;
1501 srand( Game_level_seed );
1503 // semirand function needs to get re-initted every time in multiplayer
1504 if ( Game_mode & GM_MULTIPLAYER ){
1510 Key_normal_game = (Game_mode & GM_NORMAL);
1513 Game_shudder_time = -1;
1515 // Initialize the game subsystems
1516 // timestamp_reset(); // Must be inited before everything else
1518 game_reset_time(); // resets time, and resets saved time too
1520 obj_init(); // Must be inited before the other systems
1521 model_free_all(); // Free all existing models
1522 mission_brief_common_init(); // Free all existing briefing/debriefing text
1523 weapon_level_init();
1524 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1526 player_level_init();
1527 shipfx_flash_init(); // Init the ship gun flash system.
1528 game_flash_reset(); // Reset the flash effect
1529 particle_init(); // Reset the particle system
1533 shield_hit_init(); // Initialize system for showing shield hits
1534 radar_mission_init();
1535 mission_init_goals();
1538 obj_snd_level_init(); // init object-linked persistant sounds
1540 shockwave_level_init();
1541 afterburner_level_init();
1542 scoring_level_init( &Player->stats );
1544 asteroid_level_init();
1545 control_config_clear_used_status();
1546 collide_ship_ship_sounds_init();
1548 Pre_player_entry = 1; // Means the player has not yet entered.
1549 Entry_delay_time = 0; // Could get overwritten in mission read.
1550 fireball_preload(); // page in warphole bitmaps
1552 flak_level_init(); // initialize flak - bitmaps, etc
1553 ct_level_init(); // initialize ships contrails, etc
1554 awacs_level_init(); // initialize AWACS
1555 beam_level_init(); // initialize beam weapons
1556 mflash_level_init();
1558 supernova_level_init();
1560 // multiplayer dogfight hack
1563 shipfx_engine_wash_level_init();
1567 Last_view_target = NULL;
1572 // campaign wasn't ended
1573 Campaign_ended_in_mission = 0;
1576 // called when a mission is over -- does server specific stuff.
1577 void freespace_stop_mission()
1580 Game_mode &= ~GM_IN_MISSION;
1583 // called at frame interval to process networking stuff
1584 void game_do_networking()
1586 Assert( Net_player != NULL );
1587 if (!(Game_mode & GM_MULTIPLAYER)){
1591 // see if this player should be reading/writing data. Bit is set when at join
1592 // screen onward until quits back to main menu.
1593 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1597 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1600 multi_pause_do_frame();
1605 // Loads the best palette for this level, based
1606 // on nebula color and hud color. You could just call palette_load_table with
1607 // the appropriate filename, but who wants to do that.
1608 void game_load_palette()
1610 char palette_filename[1024];
1612 // We only use 3 hud colors right now
1613 // Assert( HUD_config.color >= 0 );
1614 // Assert( HUD_config.color <= 2 );
1616 Assert( Mission_palette >= 0 );
1617 Assert( Mission_palette <= 98 );
1619 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1620 strcpy( palette_filename, NOX("gamepalette-subspace") );
1622 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1625 mprintf(( "Loading palette %s\n", palette_filename ));
1627 // palette_load_table(palette_filename);
1630 void game_post_level_init()
1632 // Stuff which gets called after mission is loaded. Because player isn't created until
1633 // after mission loads, some things must get initted after the level loads
1635 model_level_post_init();
1638 hud_setup_escort_list();
1639 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1645 game_event_debug_init();
1648 training_mission_init();
1649 asteroid_create_all();
1651 game_framerate_check_init();
1655 // An estimate as to how high the count passed to game_loading_callback will go.
1656 // This is just a guess, it seems to always be about the same. The count is
1657 // proportional to the code being executed, not the time, so this works good
1658 // for a bar, assuming the code does about the same thing each time you
1659 // load a level. You can find this value by looking at the return value
1660 // of game_busy_callback(NULL), which I conveniently print out to the
1661 // debug output window with the '=== ENDING LOAD ==' stuff.
1662 //#define COUNT_ESTIMATE 3706
1663 #define COUNT_ESTIMATE 1111
1665 int Game_loading_callback_inited = 0;
1667 int Game_loading_background = -1;
1668 anim * Game_loading_ani = NULL;
1669 anim_instance *Game_loading_ani_instance;
1670 int Game_loading_frame=-1;
1672 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1681 // This gets called 10x per second and count is the number of times
1682 // game_busy() has been called since the current callback function
1684 void game_loading_callback(int count)
1686 game_do_networking();
1688 Assert( Game_loading_callback_inited==1 );
1689 Assert( Game_loading_ani != NULL );
1691 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1692 if ( framenum > Game_loading_ani->total_frames-1 ) {
1693 framenum = Game_loading_ani->total_frames-1;
1694 } else if ( framenum < 0 ) {
1699 while ( Game_loading_frame < framenum ) {
1700 Game_loading_frame++;
1701 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1705 if ( cbitmap > -1 ) {
1706 if ( Game_loading_background > -1 ) {
1707 gr_set_bitmap( Game_loading_background );
1711 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1712 gr_set_bitmap( cbitmap );
1713 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1715 bm_release(cbitmap);
1721 void game_loading_callback_init()
1723 Assert( Game_loading_callback_inited==0 );
1725 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1726 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1729 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1730 Assert( Game_loading_ani != NULL );
1731 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1732 Assert( Game_loading_ani_instance != NULL );
1733 Game_loading_frame = -1;
1735 Game_loading_callback_inited = 1;
1737 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1742 void game_loading_callback_close()
1744 Assert( Game_loading_callback_inited==1 );
1746 // Make sure bar shows all the way over.
1747 game_loading_callback(COUNT_ESTIMATE);
1749 int real_count = game_busy_callback( NULL );
1752 Game_loading_callback_inited = 0;
1755 mprintf(( "=================== ENDING LOAD ================\n" ));
1756 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1757 mprintf(( "================================================\n" ));
1759 // to remove warnings in release build
1763 free_anim_instance(Game_loading_ani_instance);
1764 Game_loading_ani_instance = NULL;
1765 anim_free(Game_loading_ani);
1766 Game_loading_ani = NULL;
1768 bm_release( Game_loading_background );
1769 common_free_interface_palette(); // restore game palette
1770 Game_loading_background = -1;
1772 gr_set_font( FONT1 );
1775 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1777 void game_maybe_update_sound_environment()
1779 // do nothing for now
1782 // Assign the sound environment for the game, based on the current mission
1784 void game_assign_sound_environment()
1787 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1788 Game_sound_env.id = SND_ENV_DRUGGED;
1789 Game_sound_env.volume = 0.800f;
1790 Game_sound_env.damping = 1.188f;
1791 Game_sound_env.decay = 6.392f;
1793 } else if (Num_asteroids > 30) {
1794 Game_sound_env.id = SND_ENV_AUDITORIUM;
1795 Game_sound_env.volume = 0.603f;
1796 Game_sound_env.damping = 0.5f;
1797 Game_sound_env.decay = 4.279f;
1800 Game_sound_env = Game_default_sound_env;
1804 Game_sound_env = Game_default_sound_env;
1805 Game_sound_env_update_timestamp = timestamp(1);
1808 // function which gets called before actually entering the mission. It is broken down into a funciton
1809 // since it will get called in one place from a single player game and from another place for
1810 // a multiplayer game
1811 void freespace_mission_load_stuff()
1813 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1814 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1815 if(!(Game_mode & GM_STANDALONE_SERVER)){
1817 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1819 game_loading_callback_init();
1821 event_music_level_init(); // preloads the first 2 seconds for each event music track
1824 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1827 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1830 ship_assign_sound_all(); // assign engine sounds to ships
1831 game_assign_sound_environment(); // assign the sound environment for this mission
1834 // call function in missionparse.cpp to fixup player/ai stuff.
1835 mission_parse_fixup_players();
1838 // Load in all the bitmaps for this level
1843 game_loading_callback_close();
1845 // the only thing we need to call on the standalone for now.
1847 // call function in missionparse.cpp to fixup player/ai stuff.
1848 mission_parse_fixup_players();
1850 // Load in all the bitmaps for this level
1856 uint load_mission_load;
1857 uint load_post_level_init;
1858 uint load_mission_stuff;
1860 // tells the server to load the mission and initialize structures
1861 int game_start_mission()
1863 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1865 load_gl_init = time(NULL);
1867 load_gl_init = time(NULL) - load_gl_init;
1869 if (Game_mode & GM_MULTIPLAYER) {
1870 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1872 // clear multiplayer stats
1873 init_multiplayer_stats();
1876 load_mission_load = time(NULL);
1877 if (mission_load()) {
1878 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1879 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1880 gameseq_post_event(GS_EVENT_MAIN_MENU);
1882 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1887 load_mission_load = time(NULL) - load_mission_load;
1889 // If this is a red alert mission in campaign mode, bash wingman status
1890 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1891 red_alert_bash_wingman_status();
1894 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1895 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1896 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1897 // game_load_palette();
1900 load_post_level_init = time(NULL);
1901 game_post_level_init();
1902 load_post_level_init = time(NULL) - load_post_level_init;
1906 void Do_model_timings_test();
1907 Do_model_timings_test();
1911 load_mission_stuff = time(NULL);
1912 freespace_mission_load_stuff();
1913 load_mission_stuff = time(NULL) - load_mission_stuff;
1918 int Interface_framerate = 0;
1921 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1922 DCF_BOOL( show_framerate, Show_framerate )
1923 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1924 DCF_BOOL( show_target_weapons, Show_target_weapons )
1925 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1926 DCF_BOOL( sound, Sound_enabled )
1927 DCF_BOOL( zbuffer, game_zbuffer )
1928 DCF_BOOL( shield_system, New_shield_system )
1929 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1930 DCF_BOOL( player_attacking, Player_attacking_enabled )
1931 DCF_BOOL( show_waypoints, Show_waypoints )
1932 DCF_BOOL( show_area_effect, Show_area_effect )
1933 DCF_BOOL( show_net_stats, Show_net_stats )
1934 DCF_BOOL( log, Log_debug_output_to_file )
1935 DCF_BOOL( training_msg_method, Training_msg_method )
1936 DCF_BOOL( show_player_pos, Show_player_pos )
1937 DCF_BOOL(i_framerate, Interface_framerate )
1939 DCF(show_mem,"Toggles showing mem usage")
1942 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1943 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1944 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1945 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1951 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1953 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1954 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1958 DCF(show_cpu,"Toggles showing cpu usage")
1961 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1962 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1963 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1964 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1970 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1972 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1973 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1980 // AL 4-8-98: always allow players to display their framerate
1983 DCF_BOOL( show_framerate, Show_framerate )
1990 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1993 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1994 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1995 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1996 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1998 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" );
1999 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2001 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2004 DCF(palette_flash,"Toggles palette flash effect on/off")
2007 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2008 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2009 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2010 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2012 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2013 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2016 int Use_low_mem = 0;
2018 DCF(low_mem,"Uses low memory settings regardless of RAM")
2021 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2022 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2023 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2024 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2026 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2027 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2029 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2035 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2038 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2039 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2040 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2041 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2043 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2044 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2045 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2049 int Framerate_delay = 0;
2051 float Freespace_gamma = 1.0f;
2053 DCF(gamma,"Sets Gamma factor")
2056 dc_get_arg(ARG_FLOAT|ARG_NONE);
2057 if ( Dc_arg_type & ARG_FLOAT ) {
2058 Freespace_gamma = Dc_arg_float;
2060 dc_printf( "Gamma reset to 1.0f\n" );
2061 Freespace_gamma = 1.0f;
2063 if ( Freespace_gamma < 0.1f ) {
2064 Freespace_gamma = 0.1f;
2065 } else if ( Freespace_gamma > 5.0f ) {
2066 Freespace_gamma = 5.0f;
2068 gr_set_gamma(Freespace_gamma);
2070 char tmp_gamma_string[32];
2071 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2072 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2076 dc_printf( "Usage: gamma <float>\n" );
2077 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2078 Dc_status = 0; // don't print status if help is printed. Too messy.
2082 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2091 Game_current_mission_filename[0] = 0;
2093 // seed the random number generator
2094 Game_init_seed = time(NULL);
2095 srand( Game_init_seed );
2097 Framerate_delay = 0;
2103 extern void bm_init();
2109 // Initialize the timer before the os
2117 GetCurrentDirectory(1024, whee);
2120 getcwd (whee, 1024);
2123 strcat(whee, EXE_FNAME);
2125 //Initialize the libraries
2126 s1 = timer_get_milliseconds();
2127 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2130 e1 = timer_get_milliseconds();
2132 // time a bunch of cfopens
2134 s2 = timer_get_milliseconds();
2136 for(int idx=0; idx<10000; idx++){
2137 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2142 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2144 e2 = timer_get_milliseconds();
2147 if (Is_standalone) {
2148 std_init_standalone();
2150 os_init( Osreg_class_name, Osreg_app_name );
2151 os_set_title(Osreg_title);
2154 // initialize localization module. Make sure this is down AFTER initialzing OS.
2155 // int t1 = timer_get_milliseconds();
2158 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2160 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2163 // verify that he has a valid weapons.tbl
2164 verify_weapons_tbl();
2166 // Output version numbers to registry for auto patching purposes
2167 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2168 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2169 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2171 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2172 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2173 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2176 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2180 Asteroids_enabled = 1;
2183 /////////////////////////////
2185 /////////////////////////////
2190 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2191 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2193 if (!stricmp(ptr, NOX("no sound"))) {
2194 Cmdline_freespace_no_sound = 1;
2196 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2198 } else if (!stricmp(ptr, NOX("EAX"))) {
2203 if (!Is_standalone) {
2204 snd_init(use_a3d, use_eax);
2206 /////////////////////////////
2208 /////////////////////////////
2210 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2213 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);
2215 // fire up the UpdateLauncher executable
2217 PROCESS_INFORMATION pi;
2219 memset( &si, 0, sizeof(STARTUPINFO) );
2222 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2223 NULL, // pointer to command line string
2224 NULL, // pointer to process security attributes
2225 NULL, // pointer to thread security attributes
2226 FALSE, // handle inheritance flag
2227 CREATE_DEFAULT_ERROR_MODE, // creation flags
2228 NULL, // pointer to new environment block
2229 NULL, // pointer to current directory name
2230 &si, // pointer to STARTUPINFO
2231 &pi // pointer to PROCESS_INFORMATION
2234 // If the Launcher could not be started up, let the user know
2236 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2245 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2247 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);
2255 // check for hi res pack file
2256 int has_sparky_hi = 0;
2258 // check if sparky_hi exists -- access mode 0 means does file exist
2261 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2264 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2267 // see if we've got 32 bit in the string
2268 if(strstr(ptr, "32 bit")){
2275 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2277 // always 640 for E3
2278 gr_init(GR_640, GR_GLIDE);
2280 // regular or hi-res ?
2282 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2284 if(strstr(ptr, NOX("(1024x768)"))){
2286 gr_init(GR_1024, GR_GLIDE);
2288 gr_init(GR_640, GR_GLIDE);
2291 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2293 // always 640 for E3
2295 gr_init(GR_640, GR_DIRECT3D, depth);
2297 // regular or hi-res ?
2299 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2301 if(strstr(ptr, NOX("(1024x768)"))){
2305 gr_init(GR_1024, GR_DIRECT3D, depth);
2309 gr_init(GR_640, GR_DIRECT3D, depth);
2315 if ( Use_fullscreen_at_startup && !Is_standalone) {
2316 gr_init(GR_640, GR_DIRECTDRAW);
2318 gr_init(GR_640, GR_SOFTWARE);
2321 if ( !Is_standalone ) {
2322 gr_init(GR_640, GR_DIRECTDRAW);
2324 gr_init(GR_640, GR_SOFTWARE);
2329 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2330 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2331 gr_init(GR_1024, GR_OPENGL);
2333 gr_init(GR_640, GR_OPENGL);
2337 gr_init(GR_640, GR_SOFTWARE);
2342 extern int Gr_inited;
2343 if(trying_d3d && !Gr_inited){
2345 extern char Device_init_error[512];
2346 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2355 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2356 Freespace_gamma = (float)atof(ptr);
2357 if ( Freespace_gamma == 0.0f ) {
2358 Freespace_gamma = 1.80f;
2359 } else if ( Freespace_gamma < 0.1f ) {
2360 Freespace_gamma = 0.1f;
2361 } else if ( Freespace_gamma > 5.0f ) {
2362 Freespace_gamma = 5.0f;
2364 char tmp_gamma_string[32];
2365 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2366 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2368 gr_set_gamma(Freespace_gamma);
2370 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2373 display_title_screen();
2377 // attempt to load up master tracker registry info (login and password)
2378 Multi_tracker_id = -1;
2380 // pxo login and password
2381 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2383 nprintf(("Network","Error reading in PXO login data\n"));
2384 strcpy(Multi_tracker_login,"");
2386 strcpy(Multi_tracker_login,ptr);
2388 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2390 nprintf(("Network","Error reading PXO password\n"));
2391 strcpy(Multi_tracker_passwd,"");
2393 strcpy(Multi_tracker_passwd,ptr);
2396 // pxo squad name and password
2397 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2399 nprintf(("Network","Error reading in PXO squad name\n"));
2400 strcpy(Multi_tracker_squad_name, "");
2402 strcpy(Multi_tracker_squad_name, ptr);
2405 // If less than 48MB of RAM, use low memory model.
2408 (Freespace_total_ram < 48*1024*1024) ||
2411 mprintf(( "Using normal memory settings...\n" ));
2412 bm_set_low_mem(1); // Use every other frame of bitmaps
2414 mprintf(( "Using high memory settings...\n" ));
2415 bm_set_low_mem(0); // Use all frames of bitmaps
2418 // load non-darkening pixel defs
2419 palman_load_pixels();
2421 // hud shield icon stuff
2422 hud_shield_game_init();
2424 control_config_common_init(); // sets up localization stuff in the control config
2430 gamesnd_parse_soundstbl();
2435 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2440 player_controls_init();
2443 //if(!Is_standalone){
2451 ship_init(); // read in ships.tbl
2453 mission_campaign_init(); // load in the default campaign
2455 // navmap_init(); // init the navigation map system
2456 context_help_init();
2457 techroom_intel_init(); // parse species.tbl, load intel info
2459 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2460 init_animating_pointer();
2462 mission_brief_common_init(); // Mark all the briefing structures as empty.
2463 gr_font_init(); // loads up all fonts
2465 neb2_init(); // fullneb stuff
2469 player_tips_init(); // helpful tips
2472 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2473 pilot_load_pic_list();
2474 pilot_load_squad_pic_list();
2476 load_animating_pointer(NOX("cursor"), 0, 0);
2478 // initialize alpha colors
2479 alpha_colors_init();
2482 // Game_music_paused = 0;
2489 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2490 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2492 mprintf(("cfile_init() took %d\n", e1 - s1));
2493 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2496 char transfer_text[128];
2498 float Start_time = 0.0f;
2500 float Framerate = 0.0f;
2502 float Timing_total = 0.0f;
2503 float Timing_render2 = 0.0f;
2504 float Timing_render3 = 0.0f;
2505 float Timing_flip = 0.0f;
2506 float Timing_clear = 0.0f;
2508 MONITOR(NumPolysDrawn);
2514 void game_get_framerate()
2516 char text[128] = "";
2518 if ( frame_int == -1 ) {
2520 for (i=0; i<FRAME_FILTER; i++ ) {
2521 frametimes[i] = 0.0f;
2526 frametotal -= frametimes[frame_int];
2527 frametotal += flFrametime;
2528 frametimes[frame_int] = flFrametime;
2529 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2531 if ( frametotal != 0.0 ) {
2532 if ( Framecount >= FRAME_FILTER )
2533 Framerate = FRAME_FILTER / frametotal;
2535 Framerate = Framecount / frametotal;
2536 sprintf( text, NOX("FPS: %.1f"), Framerate );
2538 sprintf( text, NOX("FPS: ?") );
2542 if (Show_framerate) {
2543 gr_set_color_fast(&HUD_color_debug);
2544 gr_string( 570, 2, text );
2548 void game_show_framerate()
2552 cur_time = f2fl(timer_get_approx_seconds());
2553 if (cur_time - Start_time > 30.0f) {
2554 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2555 Start_time += 1000.0f;
2558 //mprintf(( "%s\n", text ));
2561 if ( Debug_dump_frames )
2565 // possibly show control checking info
2566 control_check_indicate();
2568 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2569 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2570 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2571 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2574 if ( Show_cpu == 1 ) {
2579 dy = gr_get_font_height() + 1;
2581 gr_set_color_fast(&HUD_color_debug);
2585 extern int D3D_textures_in;
2586 extern int D3D_textures_in_frame;
2587 extern int Glide_textures_in;
2588 extern int Glide_textures_in_frame;
2589 extern int Glide_explosion_vram;
2590 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2592 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2594 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2598 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2600 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2602 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2604 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2606 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2611 extern int Num_pairs; // Number of object pairs that were checked.
2612 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2615 extern int Num_pairs_checked; // What percent of object pairs were checked.
2616 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2618 Num_pairs_checked = 0;
2622 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2625 if ( Timing_total > 0.01f ) {
2626 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2628 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2630 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2632 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2634 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2644 dy = gr_get_font_height() + 1;
2646 gr_set_color_fast(&HUD_color_debug);
2649 extern int TotalRam;
2650 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2655 extern int Model_ram;
2656 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2660 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2662 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2664 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2668 extern int D3D_textures_in;
2669 extern int Glide_textures_in;
2670 extern int Glide_textures_in_frame;
2671 extern int Glide_explosion_vram;
2672 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2674 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2676 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2683 if ( Show_player_pos ) {
2687 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));
2690 MONITOR_INC(NumPolys, modelstats_num_polys);
2691 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2692 MONITOR_INC(NumVerts, modelstats_num_verts );
2694 modelstats_num_polys = 0;
2695 modelstats_num_polys_drawn = 0;
2696 modelstats_num_verts = 0;
2697 modelstats_num_sortnorms = 0;
2701 void game_show_standalone_framerate()
2703 float frame_rate=30.0f;
2704 if ( frame_int == -1 ) {
2706 for (i=0; i<FRAME_FILTER; i++ ) {
2707 frametimes[i] = 0.0f;
2712 frametotal -= frametimes[frame_int];
2713 frametotal += flFrametime;
2714 frametimes[frame_int] = flFrametime;
2715 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2717 if ( frametotal != 0.0 ) {
2718 if ( Framecount >= FRAME_FILTER ){
2719 frame_rate = FRAME_FILTER / frametotal;
2721 frame_rate = Framecount / frametotal;
2724 std_set_standalone_fps(frame_rate);
2728 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2729 void game_show_time_left()
2733 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2734 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2735 // checking how much time is left
2737 if ( Mission_end_time == -1 ){
2741 diff = f2i(Mission_end_time - Missiontime);
2742 // be sure to bash to 0. diff could be negative on frame that we quit mission
2747 hud_set_default_color();
2748 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2751 //========================================================================================
2752 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2753 //========================================================================================
2757 DCF(ai_pause,"Pauses ai")
2760 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2761 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2762 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2763 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2766 obj_init_all_ships_physics();
2769 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2770 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2773 DCF(single_step,"Single steps the game")
2776 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2777 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2778 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2779 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2781 last_single_step = 0; // Make so single step waits a frame before stepping
2784 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2785 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2788 DCF_BOOL(physics_pause, physics_paused)
2789 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2790 DCF_BOOL(ai_firing, Ai_firing_enabled )
2792 // Create some simple aliases to these commands...
2793 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2794 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2795 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2796 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2797 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2800 //========================================================================================
2801 //========================================================================================
2804 void game_training_pause_do()
2808 key = game_check_key();
2810 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2817 void game_increase_skill_level()
2820 if (Game_skill_level >= NUM_SKILL_LEVELS){
2821 Game_skill_level = 0;
2825 int Player_died_time;
2827 int View_percent = 100;
2830 DCF(view, "Sets the percent of the 3d view to render.")
2833 dc_get_arg(ARG_INT);
2834 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2835 View_percent = Dc_arg_int;
2837 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2843 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2847 dc_printf("View is set to %d%%\n", View_percent );
2852 // Set the clip region for the 3d rendering window
2853 void game_set_view_clip()
2855 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2856 // Set the clip region for the letterbox "dead view"
2857 int yborder = gr_screen.max_h/4;
2859 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2860 // J.S. I've changed my ways!! See the new "no constants" code!!!
2861 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2863 // Set the clip region for normal view
2864 if ( View_percent >= 100 ) {
2867 int xborder, yborder;
2869 if ( View_percent < 5 ) {
2873 float fp = i2fl(View_percent)/100.0f;
2874 int fi = fl2i(fl_sqrt(fp)*100.0f);
2875 if ( fi > 100 ) fi=100;
2877 xborder = ( gr_screen.max_w*(100-fi) )/200;
2878 yborder = ( gr_screen.max_h*(100-fi) )/200;
2880 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2886 void show_debug_stuff()
2889 int laser_count = 0, missile_count = 0;
2891 for (i=0; i<MAX_OBJECTS; i++) {
2892 if (Objects[i].type == OBJ_WEAPON){
2893 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2895 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2901 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2904 extern int Tool_enabled;
2909 int tst_bitmap = -1;
2911 float tst_offset, tst_offset_total;
2914 void game_tst_frame_pre()
2922 g3_rotate_vertex(&v, &tst_pos);
2923 g3_project_vertex(&v);
2926 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2930 // big ship? always tst
2932 // within 3000 meters
2933 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2937 // within 300 meters
2938 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2945 void game_tst_frame()
2955 tst_time = time(NULL);
2957 // load the tst bitmap
2958 switch((int)frand_range(0.0f, 3.0)){
2960 tst_bitmap = bm_load("ig_jim");
2962 mprintf(("TST 0\n"));
2966 tst_bitmap = bm_load("ig_kan");
2968 mprintf(("TST 1\n"));
2972 tst_bitmap = bm_load("ig_jim");
2974 mprintf(("TST 2\n"));
2978 tst_bitmap = bm_load("ig_kan");
2980 mprintf(("TST 3\n"));
2989 // get the tst bitmap dimensions
2991 bm_get_info(tst_bitmap, &w, &h);
2994 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2996 snd_play(&Snds[SND_VASUDAN_BUP]);
2998 // tst x and direction
3002 tst_offset_total = (float)w;
3003 tst_offset = (float)w;
3005 tst_x = (float)gr_screen.max_w;
3006 tst_offset_total = (float)-w;
3007 tst_offset = (float)w;
3015 float diff = (tst_offset_total / 0.5f) * flFrametime;
3021 tst_offset -= fl_abs(diff);
3022 } else if(tst_mode == 2){
3025 tst_offset -= fl_abs(diff);
3029 gr_set_bitmap(tst_bitmap);
3030 gr_bitmap((int)tst_x, (int)tst_y);
3033 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3037 // if we passed the switch point
3038 if(tst_offset <= 0.0f){
3043 tst_stamp = timestamp(1000);
3044 tst_offset = fl_abs(tst_offset_total);
3055 void game_tst_mark(object *objp, ship *shipp)
3064 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3067 sip = &Ship_info[shipp->ship_info_index];
3074 tst_pos = objp->pos;
3075 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3081 extern void render_shields();
3083 void player_repair_frame(float frametime)
3085 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3087 for(idx=0;idx<MAX_PLAYERS;idx++){
3090 np = &Net_players[idx];
3092 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)){
3094 // don't rearm/repair if the player is dead or dying/departing
3095 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3096 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3101 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3102 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3108 #define NUM_FRAMES_TEST 300
3109 #define NUM_MIXED_SOUNDS 16
3110 void do_timing_test(float flFrametime)
3112 static int framecount = 0;
3113 static int test_running = 0;
3114 static float test_time = 0.0f;
3116 static int snds[NUM_MIXED_SOUNDS];
3119 if ( test_running ) {
3121 test_time += flFrametime;
3122 if ( framecount >= NUM_FRAMES_TEST ) {
3124 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3125 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3130 if ( Test_begin == 1 ) {
3136 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3139 // start looping digital sounds
3140 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3141 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3148 DCF(dcf_fov, "Change the field of view")
3151 dc_get_arg(ARG_FLOAT|ARG_NONE);
3152 if ( Dc_arg_type & ARG_NONE ) {
3153 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3154 dc_printf( "Zoom factor reset\n" );
3156 if ( Dc_arg_type & ARG_FLOAT ) {
3157 if (Dc_arg_float < 0.25f) {
3158 Viewer_zoom = 0.25f;
3159 dc_printf("Zoom factor pinned at 0.25.\n");
3160 } else if (Dc_arg_float > 1.25f) {
3161 Viewer_zoom = 1.25f;
3162 dc_printf("Zoom factor pinned at 1.25.\n");
3164 Viewer_zoom = Dc_arg_float;
3170 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3173 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3177 DCF(framerate_cap, "Sets the framerate cap")
3180 dc_get_arg(ARG_INT);
3181 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3182 Framerate_cap = Dc_arg_int;
3184 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3190 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3191 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3192 dc_printf("[n] must be from 1 to 120.\n");
3196 if ( Framerate_cap )
3197 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3199 dc_printf("There is no framerate cap currently active.\n");
3203 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3204 int Show_viewing_from_self = 0;
3206 void say_view_target()
3208 object *view_target;
3210 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3211 view_target = &Objects[Player_ai->target_objnum];
3213 view_target = Player_obj;
3215 if (Game_mode & GM_DEAD) {
3216 if (Player_ai->target_objnum != -1)
3217 view_target = &Objects[Player_ai->target_objnum];
3220 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3221 if (view_target != Player_obj){
3223 char *view_target_name = NULL;
3224 switch(Objects[Player_ai->target_objnum].type) {
3226 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3229 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3230 Viewer_mode &= ~VM_OTHER_SHIP;
3232 case OBJ_JUMP_NODE: {
3233 char jump_node_name[128];
3234 strcpy(jump_node_name, XSTR( "jump node", 184));
3235 view_target_name = jump_node_name;
3236 Viewer_mode &= ~VM_OTHER_SHIP;
3245 if ( view_target_name ) {
3246 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3247 Show_viewing_from_self = 1;
3250 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3251 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3252 Show_viewing_from_self = 1;
3254 if (Show_viewing_from_self)
3255 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3260 Last_view_target = view_target;
3264 float Game_hit_x = 0.0f;
3265 float Game_hit_y = 0.0f;
3267 // Reset at the beginning of each frame
3268 void game_whack_reset()
3274 // Apply a 2d whack to the player
3275 void game_whack_apply( float x, float y )
3277 // Do some force feedback
3278 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3284 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3287 // call to apply a "shudder"
3288 void game_shudder_apply(int time, float intensity)
3290 Game_shudder_time = timestamp(time);
3291 Game_shudder_total = time;
3292 Game_shudder_intensity = intensity;
3295 #define FF_SCALE 10000
3296 void apply_hud_shake(matrix *eye_orient)
3298 if (Viewer_obj == Player_obj) {
3299 physics_info *pi = &Player_obj->phys_info;
3307 // Make eye shake due to afterburner
3308 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3311 dtime = timestamp_until(pi->afterburner_decay);
3315 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3316 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3319 // Make eye shake due to engine wash
3321 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3324 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3325 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3327 // get the intensity
3328 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3332 vm_vec_rand_vec_quick(&rand_vec);
3335 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3339 // make hud shake due to shuddering
3340 if(Game_shudder_time != -1){
3341 // if the timestamp has elapsed
3342 if(timestamp_elapsed(Game_shudder_time)){
3343 Game_shudder_time = -1;
3345 // otherwise apply some shudder
3349 dtime = timestamp_until(Game_shudder_time);
3353 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));
3354 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));
3359 vm_angles_2_matrix(&tm, &tangles);
3360 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3361 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3362 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3363 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3368 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3370 // Player's velocity just before he blew up. Used to keep camera target moving.
3371 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3373 // Set eye_pos and eye_orient based on view mode.
3374 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3378 static int last_Viewer_mode = 0;
3379 static int last_Game_mode = 0;
3380 static int last_Viewer_objnum = -1;
3382 // This code is supposed to detect camera "cuts"... like going between
3385 // determine if we need to regenerate the nebula
3386 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3387 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3388 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3389 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3390 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3391 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3392 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3393 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3394 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3397 // regenerate the nebula
3401 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3402 //mprintf(( "************** Camera cut! ************\n" ));
3403 last_Viewer_mode = Viewer_mode;
3404 last_Game_mode = Game_mode;
3406 // Camera moved. Tell stars & debris to not do blurring.
3412 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3413 player_display_packlock_view();
3416 game_set_view_clip();
3418 if (Game_mode & GM_DEAD) {
3419 vector vec_to_deader, view_pos;
3422 Viewer_mode |= VM_DEAD_VIEW;
3424 if (Player_ai->target_objnum != -1) {
3425 int view_from_player = 1;
3427 if (Viewer_mode & VM_OTHER_SHIP) {
3428 // View from target.
3429 Viewer_obj = &Objects[Player_ai->target_objnum];
3431 last_Viewer_objnum = Player_ai->target_objnum;
3433 if ( Viewer_obj->type == OBJ_SHIP ) {
3434 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3435 view_from_player = 0;
3438 last_Viewer_objnum = -1;
3441 if ( view_from_player ) {
3442 // View target from player ship.
3444 *eye_pos = Player_obj->pos;
3445 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3446 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3449 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3451 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3452 dist += flFrametime * 16.0f;
3454 vm_vec_scale(&vec_to_deader, -dist);
3455 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3457 view_pos = Player_obj->pos;
3459 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3460 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3461 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3462 Dead_player_last_vel = Player_obj->phys_info.vel;
3463 //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));
3464 } else if (Player_ai->target_objnum != -1) {
3465 view_pos = Objects[Player_ai->target_objnum].pos;
3467 // Make camera follow explosion, but gradually slow down.
3468 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3469 view_pos = Player_obj->pos;
3470 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3471 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3474 *eye_pos = Dead_camera_pos;
3476 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3478 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3483 // if supernova shockwave
3484 if(supernova_camera_cut()){
3488 // call it dead view
3489 Viewer_mode |= VM_DEAD_VIEW;
3491 // set eye pos and orient
3492 supernova_set_view(eye_pos, eye_orient);
3494 // If already blown up, these other modes can override.
3495 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3496 Viewer_mode &= ~VM_DEAD_VIEW;
3498 Viewer_obj = Player_obj;
3500 if (Viewer_mode & VM_OTHER_SHIP) {
3501 if (Player_ai->target_objnum != -1){
3502 Viewer_obj = &Objects[Player_ai->target_objnum];
3503 last_Viewer_objnum = Player_ai->target_objnum;
3505 Viewer_mode &= ~VM_OTHER_SHIP;
3506 last_Viewer_objnum = -1;
3509 last_Viewer_objnum = -1;
3512 if (Viewer_mode & VM_EXTERNAL) {
3515 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3516 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3518 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3520 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3521 vm_vec_normalize(&eye_dir);
3522 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3525 // Modify the orientation based on head orientation.
3526 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3528 } else if ( Viewer_mode & VM_CHASE ) {
3531 if ( Viewer_obj->phys_info.speed < 0.1 )
3532 move_dir = Viewer_obj->orient.v.fvec;
3534 move_dir = Viewer_obj->phys_info.vel;
3535 vm_vec_normalize(&move_dir);
3538 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3539 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3540 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3541 vm_vec_normalize(&eye_dir);
3543 // JAS: I added the following code because if you slew up using
3544 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3545 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3546 // call because the up and the forward vector are the same. I fixed
3547 // it by adding in a fraction of the right vector all the time to the
3549 vector tmp_up = Viewer_obj->orient.v.uvec;
3550 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3552 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3555 // Modify the orientation based on head orientation.
3556 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3557 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3558 *eye_pos = Camera_pos;
3560 ship * shipp = &Ships[Player_obj->instance];
3562 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3563 vm_vec_normalize(&eye_dir);
3564 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3567 // get an eye position based upon the correct type of object
3568 switch(Viewer_obj->type){
3570 // make a call to get the eye point for the player object
3571 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3574 // make a call to get the eye point for the player object
3575 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3581 #ifdef JOHNS_DEBUG_CODE
3582 john_debug_stuff(&eye_pos, &eye_orient);
3588 apply_hud_shake(eye_orient);
3590 // setup neb2 rendering
3591 neb2_render_setup(eye_pos, eye_orient);
3595 extern void ai_debug_render_stuff();
3598 int Game_subspace_effect = 0;
3599 DCF_BOOL( subspace, Game_subspace_effect );
3601 // Does everything needed to render a frame
3602 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3606 g3_start_frame(game_zbuffer);
3607 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3609 // maybe offset the HUD (jitter stuff)
3610 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3611 HUD_set_offsets(Viewer_obj, !dont_offset);
3613 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3614 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3615 // must be done before ships are rendered
3616 if ( MULTIPLAYER_CLIENT ) {
3617 shield_point_multi_setup();
3620 if ( Game_subspace_effect ) {
3621 stars_draw(0,0,0,1);
3623 stars_draw(1,1,1,0);
3626 obj_render_all(obj_render);
3627 beam_render_all(); // render all beam weapons
3628 particle_render_all(); // render particles after everything else.
3629 trail_render_all(); // render missilie trails after everything else.
3630 mflash_render_all(); // render all muzzle flashes
3632 // Why do we not show the shield effect in these modes? Seems ok.
3633 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3637 // render nebula lightning
3640 // render local player nebula
3641 neb2_render_player();
3644 ai_debug_render_stuff();
3647 #ifndef RELEASE_REAL
3648 // game_framerate_check();
3652 extern void snd_spew_debug_info();
3653 snd_spew_debug_info();
3656 //================ END OF 3D RENDERING STUFF ====================
3660 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3661 hud_maybe_clear_head_area();
3662 anim_render_all(0, flFrametime);
3665 extern int Multi_display_netinfo;
3666 if(Multi_display_netinfo){
3667 extern void multi_display_netinfo();
3668 multi_display_netinfo();
3671 game_tst_frame_pre();
3674 do_timing_test(flFrametime);
3678 extern int OO_update_index;
3679 multi_rate_display(OO_update_index, 375, 0);
3684 extern void oo_display();
3691 //#define JOHNS_DEBUG_CODE 1
3693 #ifdef JOHNS_DEBUG_CODE
3694 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3696 //if ( keyd_pressed[KEY_LSHIFT] )
3698 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3700 model_subsystem *turret = tsys->system_info;
3702 if (turret->type == SUBSYSTEM_TURRET ) {
3703 vector v.fvec, v.uvec;
3704 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3706 ship_model_start(tobj);
3708 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3709 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3710 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3712 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3714 ship_model_stop(tobj);
3724 // following function for dumping frames for purposes of building trailers.
3727 // function to toggle state of dumping every frame into PCX when playing the game
3728 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3732 if ( Debug_dump_frames == 0 ) {
3734 Debug_dump_frames = 15;
3735 Debug_dump_trigger = 0;
3736 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3737 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3740 Debug_dump_frames = 0;
3741 Debug_dump_trigger = 0;
3742 gr_dump_frame_stop();
3743 dc_printf( "Frame dumping is now OFF\n" );
3749 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3753 if ( Debug_dump_frames == 0 ) {
3755 Debug_dump_frames = 15;
3756 Debug_dump_trigger = 1;
3757 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3758 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3761 Debug_dump_frames = 0;
3762 Debug_dump_trigger = 0;
3763 gr_dump_frame_stop();
3764 dc_printf( "Frame dumping is now OFF\n" );
3770 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3774 if ( Debug_dump_frames == 0 ) {
3776 Debug_dump_frames = 30;
3777 Debug_dump_trigger = 0;
3778 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3779 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3782 Debug_dump_frames = 0;
3783 Debug_dump_trigger = 0;
3784 gr_dump_frame_stop();
3785 dc_printf( "Frame dumping is now OFF\n" );
3791 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3795 if ( Debug_dump_frames == 0 ) {
3797 Debug_dump_frames = 30;
3798 Debug_dump_trigger = 1;
3799 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3800 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3803 Debug_dump_frames = 0;
3804 Debug_dump_trigger = 0;
3805 gr_dump_frame_stop();
3806 dc_printf( "Triggered frame dumping is now OFF\n" );
3812 void game_maybe_dump_frame()
3814 if ( !Debug_dump_frames ){
3818 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3825 Debug_dump_frame_num++;
3831 extern int Player_dead_state;
3833 // Flip the page and time how long it took.
3834 void game_flip_page_and_time_it()
3838 t1 = timer_get_fixed_seconds();
3840 t2 = timer_get_fixed_seconds();
3842 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3843 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3846 void game_simulation_frame()
3848 // blow ships up in multiplayer dogfight
3849 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){
3850 // blow up all non-player ships
3851 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3854 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3856 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)){
3857 moveup = GET_NEXT(moveup);
3860 shipp = &Ships[Objects[moveup->objnum].instance];
3861 sip = &Ship_info[shipp->ship_info_index];
3863 // only blow up small ships
3864 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3865 // function to simply explode a ship where it is currently at
3866 ship_self_destruct( &Objects[moveup->objnum] );
3869 moveup = GET_NEXT(moveup);
3875 // process AWACS stuff - do this first thing
3878 // single player, set Player hits_this_frame to 0
3879 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3880 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3881 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3885 supernova_process();
3886 if(supernova_active() >= 5){
3890 // fire targeting lasers now so that
3891 // 1 - created this frame
3892 // 2 - collide this frame
3893 // 3 - render this frame
3894 // 4 - ignored and deleted next frame
3895 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3897 ship_process_targeting_lasers();
3899 // do this here so that it works for multiplayer
3901 // get viewer direction
3902 int viewer_direction = PHYSICS_VIEWER_REAR;
3904 if(Viewer_mode == 0){
3905 viewer_direction = PHYSICS_VIEWER_FRONT;
3907 if(Viewer_mode & VM_PADLOCK_UP){
3908 viewer_direction = PHYSICS_VIEWER_UP;
3910 else if(Viewer_mode & VM_PADLOCK_REAR){
3911 viewer_direction = PHYSICS_VIEWER_REAR;
3913 else if(Viewer_mode & VM_PADLOCK_LEFT){
3914 viewer_direction = PHYSICS_VIEWER_LEFT;
3916 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3917 viewer_direction = PHYSICS_VIEWER_RIGHT;
3920 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3922 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3925 #define VM_PADLOCK_UP (1 << 7)
3926 #define VM_PADLOCK_REAR (1 << 8)
3927 #define VM_PADLOCK_LEFT (1 << 9)
3928 #define VM_PADLOCK_RIGHT (1 << 10)
3930 // evaluate mission departures and arrivals before we process all objects.
3931 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3933 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3934 // ships/wing packets.
3935 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3936 mission_parse_eval_stuff();
3939 // if we're an observer, move ourselves seperately from the standard physics
3940 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3941 obj_observer_move(flFrametime);
3944 // move all the objects now
3945 obj_move_all(flFrametime);
3947 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3948 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3949 // ship_check_cargo_all();
3950 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3951 mission_eval_goals();
3955 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3956 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3957 training_check_objectives();
3960 // do all interpolation now
3961 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3962 // client side processing of warping in effect stages
3963 multi_do_client_warp(flFrametime);
3965 // client side movement of an observer
3966 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3967 obj_observer_move(flFrametime);
3970 // move all objects - does interpolation now as well
3971 obj_move_all(flFrametime);
3974 // only process the message queue when the player is "in" the game
3975 if ( !Pre_player_entry ){
3976 message_queue_process(); // process any messages send to the player
3979 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3980 message_maybe_distort(); // maybe distort incoming message if comms damaged
3981 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3982 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3983 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3986 if(!(Game_mode & GM_STANDALONE_SERVER)){
3987 // process some stuff every frame (before frame is rendered)
3988 emp_process_local();
3990 hud_update_frame(); // update hud systems
3992 if (!physics_paused) {
3993 // Move particle system
3994 particle_move_all(flFrametime);
3996 // Move missile trails
3997 trail_move_all(flFrametime);
3999 // process muzzle flashes
4000 mflash_process_all();
4002 // Flash the gun flashes
4003 shipfx_flash_do_frame(flFrametime);
4005 shockwave_move_all(flFrametime); // update all the shockwaves
4008 // subspace missile strikes
4011 obj_snd_do_frame(); // update the object-linked persistant sounds
4012 game_maybe_update_sound_environment();
4013 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4015 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4017 if ( Game_subspace_effect ) {
4018 game_start_subspace_ambient_sound();
4024 // Maybe render and process the dead-popup
4025 void game_maybe_do_dead_popup(float frametime)
4027 if ( popupdead_is_active() ) {
4029 int choice = popupdead_do_frame(frametime);
4031 if ( Game_mode & GM_NORMAL ) {
4035 if(game_do_cd_mission_check(Game_current_mission_filename)){
4036 gameseq_post_event(GS_EVENT_ENTER_GAME);
4038 gameseq_post_event(GS_EVENT_MAIN_MENU);
4043 gameseq_post_event(GS_EVENT_END_GAME);
4048 if(game_do_cd_mission_check(Game_current_mission_filename)){
4049 gameseq_post_event(GS_EVENT_START_GAME);
4051 gameseq_post_event(GS_EVENT_MAIN_MENU);
4055 // this should only happen during a red alert mission
4058 Assert(The_mission.red_alert);
4059 if(!The_mission.red_alert){
4061 if(game_do_cd_mission_check(Game_current_mission_filename)){
4062 gameseq_post_event(GS_EVENT_START_GAME);
4064 gameseq_post_event(GS_EVENT_MAIN_MENU);
4069 // choose the previous mission
4070 mission_campaign_previous_mission();
4072 if(game_do_cd_mission_check(Game_current_mission_filename)){
4073 gameseq_post_event(GS_EVENT_START_GAME);
4075 gameseq_post_event(GS_EVENT_MAIN_MENU);
4086 case POPUPDEAD_DO_MAIN_HALL:
4087 multi_quit_game(PROMPT_NONE,-1);
4090 case POPUPDEAD_DO_RESPAWN:
4091 multi_respawn_normal();
4092 event_music_player_respawn();
4095 case POPUPDEAD_DO_OBSERVER:
4096 multi_respawn_observer();
4097 event_music_player_respawn_as_observer();
4106 if ( leave_popup ) {
4112 // returns true if player is actually in a game_play stats
4113 int game_actually_playing()
4117 state = gameseq_get_state();
4118 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4124 // Draw the 2D HUD gauges
4125 void game_render_hud_2d()
4127 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4131 HUD_render_2d(flFrametime);
4135 // Draw the 3D-dependant HUD gauges
4136 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4138 g3_start_frame(0); // 0 = turn zbuffering off
4139 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4141 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4142 HUD_render_3d(flFrametime);
4146 game_sunspot_process(flFrametime);
4148 // Diminish the palette effect
4149 game_flash_diminish(flFrametime);
4157 int actually_playing;
4158 fix total_time1, total_time2;
4159 fix render2_time1=0, render2_time2=0;
4160 fix render3_time1=0, render3_time2=0;
4161 fix flip_time1=0, flip_time2=0;
4162 fix clear_time1=0, clear_time2=0;
4168 if (Framerate_delay) {
4169 int start_time = timer_get_milliseconds();
4170 while (timer_get_milliseconds() < start_time + Framerate_delay)
4176 demo_do_frame_start();
4178 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4183 // start timing frame
4184 timing_frame_start();
4186 total_time1 = timer_get_fixed_seconds();
4188 // var to hold which state we are in
4189 actually_playing = game_actually_playing();
4191 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4192 if (!(Game_mode & GM_STANDALONE_SERVER)){
4193 Assert( OBJ_INDEX(Player_obj) >= 0 );
4197 if (Missiontime > Entry_delay_time){
4198 Pre_player_entry = 0;
4200 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4203 // Note: These are done even before the player enters, else buffers can overflow.
4204 if (! (Game_mode & GM_STANDALONE_SERVER)){
4208 shield_frame_init();
4210 if ( Player->control_mode != PCM_NORMAL )
4213 if ( !Pre_player_entry && actually_playing ) {
4214 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4216 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4217 game_process_keys();
4219 // don't read flying controls if we're playing a demo back
4220 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4221 read_player_controls( Player_obj, flFrametime);
4225 // if we're not the master, we may have to send the server-critical ship status button_info bits
4226 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4227 multi_maybe_send_ship_status();
4232 // Reset the whack stuff
4235 // These two lines must be outside of Pre_player_entry code,
4236 // otherwise too many lights are added.
4239 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4243 game_simulation_frame();
4245 // if not actually in a game play state, then return. This condition could only be true in
4246 // a multiplayer game.
4247 if ( !actually_playing ) {
4248 Assert( Game_mode & GM_MULTIPLAYER );
4252 if (!Pre_player_entry) {
4253 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4254 clear_time1 = timer_get_fixed_seconds();
4255 // clear the screen to black
4257 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4261 clear_time2 = timer_get_fixed_seconds();
4262 render3_time1 = timer_get_fixed_seconds();
4263 game_render_frame_setup(&eye_pos, &eye_orient);
4264 game_render_frame( &eye_pos, &eye_orient );
4266 // save the eye position and orientation
4267 if ( Game_mode & GM_MULTIPLAYER ) {
4268 Net_player->s_info.eye_pos = eye_pos;
4269 Net_player->s_info.eye_orient = eye_orient;
4272 hud_show_target_model();
4274 // check to see if we should display the death died popup
4275 if(Game_mode & GM_DEAD_BLEW_UP){
4276 if(Game_mode & GM_MULTIPLAYER){
4277 // catch the situation where we're supposed to be warping out on this transition
4278 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4279 gameseq_post_event(GS_EVENT_DEBRIEF);
4280 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4281 Player_died_popup_wait = -1;
4285 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4286 Player_died_popup_wait = -1;
4292 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4293 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4294 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4295 if(!popupdead_is_active()){
4299 Player_multi_died_check = -1;
4303 render3_time2 = timer_get_fixed_seconds();
4304 render2_time1 = timer_get_fixed_seconds();
4307 game_get_framerate();
4308 game_show_framerate();
4310 game_show_time_left();
4312 // Draw the 2D HUD gauges
4313 if(supernova_active() < 3){
4314 game_render_hud_2d();
4317 game_set_view_clip();
4319 // Draw 3D HUD gauges
4320 game_render_hud_3d(&eye_pos, &eye_orient);
4324 render2_time2 = timer_get_fixed_seconds();
4326 // maybe render and process the dead popup
4327 game_maybe_do_dead_popup(flFrametime);
4329 // start timing frame
4330 timing_frame_stop();
4331 // timing_display(30, 10);
4333 // If a regular popup is active, don't flip (popup code flips)
4334 if( !popup_running_state() ){
4335 flip_time1 = timer_get_fixed_seconds();
4336 game_flip_page_and_time_it();
4337 flip_time2 = timer_get_fixed_seconds();
4341 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4344 game_show_standalone_framerate();
4348 game_do_training_checks();
4351 // process lightning (nebula only)
4354 total_time2 = timer_get_fixed_seconds();
4356 // Got some timing numbers
4357 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4358 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4359 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4360 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4361 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4364 demo_do_frame_end();
4366 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4372 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4373 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4374 // died. This resulted in screwed up death sequences.
4376 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4377 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4378 static int timer_paused=0;
4379 #if defined(TIMER_TEST) && !defined(NDEBUG)
4380 static int stop_count,start_count;
4381 static int time_stopped,time_started;
4383 int saved_timestamp_ticker = -1;
4385 void game_reset_time()
4387 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4391 // Last_time = timer_get_fixed_seconds();
4397 void game_stop_time()
4399 if (timer_paused==0) {
4401 time = timer_get_fixed_seconds();
4402 // Save how much time progressed so far in the frame so we can
4403 // use it when we unpause.
4404 Last_delta_time = time - Last_time;
4406 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4407 if (Last_delta_time < 0) {
4408 #if defined(TIMER_TEST) && !defined(NDEBUG)
4409 Int3(); //get Matt!!!!
4411 Last_delta_time = 0;
4413 #if defined(TIMER_TEST) && !defined(NDEBUG)
4414 time_stopped = time;
4417 // Stop the timer_tick stuff...
4418 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4419 saved_timestamp_ticker = timestamp_ticker;
4423 #if defined(TIMER_TEST) && !defined(NDEBUG)
4428 void game_start_time()
4431 Assert(timer_paused >= 0);
4432 if (timer_paused==0) {
4434 time = timer_get_fixed_seconds();
4435 #if defined(TIMER_TEST) && !defined(NDEBUG)
4437 Int3(); //get Matt!!!!
4440 // Take current time, and set it backwards to account for time
4441 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4442 // will be correct when it goes to calculate the frametime next
4444 Last_time = time - Last_delta_time;
4445 #if defined(TIMER_TEST) && !defined(NDEBUG)
4446 time_started = time;
4449 // Restore the timer_tick stuff...
4450 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4451 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4452 timestamp_ticker = saved_timestamp_ticker;
4453 saved_timestamp_ticker = -1;
4456 #if defined(TIMER_TEST) && !defined(NDEBUG)
4462 void game_set_frametime(int state)
4465 float frame_cap_diff;
4467 thistime = timer_get_fixed_seconds();
4469 if ( Last_time == 0 )
4470 Frametime = F1_0 / 30;
4472 Frametime = thistime - Last_time;
4474 // Frametime = F1_0 / 30;
4476 fix debug_frametime = Frametime; // Just used to display frametime.
4478 // If player hasn't entered mission yet, make frame take 1/4 second.
4479 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4482 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4484 fix frame_speed = F1_0 / Debug_dump_frames;
4486 if (Frametime > frame_speed ){
4487 nprintf(("warning","slow frame: %x\n",Frametime));
4490 thistime = timer_get_fixed_seconds();
4491 Frametime = thistime - Last_time;
4492 } while (Frametime < frame_speed );
4494 Frametime = frame_speed;
4498 Assert( Framerate_cap > 0 );
4500 // Cap the framerate so it doesn't get too high.
4504 cap = F1_0/Framerate_cap;
4505 if (Frametime < cap) {
4506 thistime = cap - Frametime;
4507 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4508 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4510 thistime = timer_get_fixed_seconds();
4514 if((Game_mode & GM_STANDALONE_SERVER) &&
4515 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4517 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4518 Sleep((DWORD)(frame_cap_diff*1000));
4520 thistime += fl2f((frame_cap_diff));
4522 Frametime = thistime - Last_time;
4525 // If framerate is too low, cap it.
4526 if (Frametime > MAX_FRAMETIME) {
4528 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4530 // to remove warnings in release build
4531 debug_frametime = fl2f(flFrametime);
4533 Frametime = MAX_FRAMETIME;
4536 Frametime = fixmul(Frametime, Game_time_compression);
4538 Last_time = thistime;
4539 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4541 flFrametime = f2fl(Frametime);
4542 //if(!(Game_mode & GM_PLAYING_DEMO)){
4543 timestamp_inc(flFrametime);
4545 /* if ((Framecount > 0) && (Framecount < 10)) {
4546 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4551 // This is called from game_do_frame(), and from navmap_do_frame()
4552 void game_update_missiontime()
4554 // TODO JAS: Put in if and move this into game_set_frametime,
4555 // fix navmap to call game_stop/start_time
4556 //if ( !timer_paused )
4557 Missiontime += Frametime;
4560 void game_do_frame()
4562 game_set_frametime(GS_STATE_GAME_PLAY);
4563 game_update_missiontime();
4565 if (Game_mode & GM_STANDALONE_SERVER) {
4566 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4569 if ( game_single_step && (last_single_step == game_single_step) ) {
4570 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4571 while( key_checkch() == 0 )
4573 os_set_title( XSTR( "FreeSpace", 171) );
4574 Last_time = timer_get_fixed_seconds();
4577 last_single_step = game_single_step;
4579 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4580 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4584 Keep_mouse_centered = 0;
4585 monitor_update(); // Update monitor variables
4588 void multi_maybe_do_frame()
4590 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4595 int Joymouse_button_status = 0;
4597 // Flush all input devices
4605 Joymouse_button_status = 0;
4607 //mprintf(("Game flush!\n" ));
4610 // function for multiplayer only which calls game_do_state_common() when running the
4612 void game_do_dc_networking()
4614 Assert( Game_mode & GM_MULTIPLAYER );
4616 game_do_state_common( gameseq_get_state() );
4619 // Call this whenever in a loop, or when you need to check for a keystroke.
4620 int game_check_key()
4626 // convert keypad enter to normal enter
4627 if ((k & KEY_MASK) == KEY_PADENTER)
4628 k = (k & ~KEY_MASK) | KEY_ENTER;
4635 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4636 static int Demo_show_trailer_timestamp = 0;
4638 void demo_reset_trailer_timer()
4640 Demo_show_trailer_timestamp = timer_get_milliseconds();
4643 void demo_maybe_show_trailer(int k)
4646 // if key pressed, reset demo trailer timer
4648 demo_reset_trailer_timer();
4652 // if mouse moved, reset demo trailer timer
4655 mouse_get_delta(&dx, &dy);
4656 if ( (dx > 0) || (dy > 0) ) {
4657 demo_reset_trailer_timer();
4661 // if joystick has moved, reset demo trailer timer
4664 joy_get_delta(&dx, &dy);
4665 if ( (dx > 0) || (dy > 0) ) {
4666 demo_reset_trailer_timer();
4670 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4671 // the low-level code. Ugly, I know... but was the simplest and most
4674 // if 30 seconds since last demo trailer time reset, launch movie
4675 if ( os_foreground() ) {
4676 int now = timer_get_milliseconds();
4677 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4678 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4680 movie_play( NOX("fstrailer2.mve") );
4681 demo_reset_trailer_timer();
4689 // same as game_check_key(), except this is used while actually in the game. Since there
4690 // generally are differences between game control keys and general UI keys, makes sense to
4691 // have seperate functions for each case. If you are not checking a game control while in a
4692 // mission, you should probably be using game_check_key() instead.
4697 if (!os_foreground()) {
4702 // If we're in a single player game, pause it.
4703 if (!(Game_mode & GM_MULTIPLAYER)){
4704 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4705 game_process_pause_key();
4713 demo_maybe_show_trailer(k);
4716 // Move the mouse cursor with the joystick.
4717 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4718 // Move the mouse cursor with the joystick
4722 joy_get_pos( &jx, &jy, &jz, &jr );
4724 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4725 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4728 mouse_get_real_pos( &mx, &my );
4729 mouse_set_pos( mx+dx, my+dy );
4734 m = mouse_down(MOUSE_LEFT_BUTTON);
4736 if ( j != Joymouse_button_status ) {
4737 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4738 Joymouse_button_status = j;
4740 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4741 } else if ( (!j) && (m) ) {
4742 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4747 // if we should be ignoring keys because of some multiplayer situations
4748 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4752 // If a popup is running, don't process all the Fn keys
4753 if( popup_active() ) {
4757 state = gameseq_get_state();
4759 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4762 case KEY_DEBUGGED + KEY_BACKSP:
4767 launch_context_help();
4772 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4774 // don't allow f2 while warping out in multiplayer
4775 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4780 case GS_STATE_INITIAL_PLAYER_SELECT:
4781 case GS_STATE_OPTIONS_MENU:
4782 case GS_STATE_HUD_CONFIG:
4783 case GS_STATE_CONTROL_CONFIG:
4784 case GS_STATE_DEATH_DIED:
4785 case GS_STATE_DEATH_BLEW_UP:
4786 case GS_STATE_VIEW_MEDALS:
4790 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4797 // hotkey selection screen -- only valid from briefing and beyond.
4800 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) ) {
4801 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4807 case KEY_DEBUGGED + KEY_F3:
4808 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4811 case KEY_DEBUGGED + KEY_F4:
4812 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4816 if(Game_mode & GM_MULTIPLAYER){
4817 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4818 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4822 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4823 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4829 case KEY_ESC | KEY_SHIFTED:
4830 // make sure to quit properly out of multiplayer
4831 if(Game_mode & GM_MULTIPLAYER){
4832 multi_quit_game(PROMPT_NONE);
4835 gameseq_post_event( GS_EVENT_QUIT_GAME );
4840 case KEY_DEBUGGED + KEY_P:
4843 case KEY_PRINT_SCRN:
4845 static int counter = 0;
4850 sprintf( tmp_name, NOX("screen%02d"), counter );
4852 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4853 gr_print_screen(tmp_name);
4861 case KEY_SHIFTED | KEY_ENTER: {
4863 #if !defined(NDEBUG)
4865 if ( Game_mode & GM_NORMAL ){
4869 // if we're in multiplayer mode, do some special networking
4870 if(Game_mode & GM_MULTIPLAYER){
4871 debug_console(game_do_dc_networking);
4878 if ( Game_mode & GM_NORMAL )
4892 gameseq_post_event(GS_EVENT_QUIT_GAME);
4895 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4898 void camera_set_position( vector *pos )
4903 void camera_set_orient( matrix *orient )
4905 Camera_orient = *orient;
4908 void camera_set_velocity( vector *vel, int instantaneous )
4910 Camera_desired_velocity.xyz.x = 0.0f;
4911 Camera_desired_velocity.xyz.y = 0.0f;
4912 Camera_desired_velocity.xyz.z = 0.0f;
4914 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4915 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4916 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4918 if ( instantaneous ) {
4919 Camera_velocity = Camera_desired_velocity;
4927 vector new_vel, delta_pos;
4929 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4930 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4931 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4933 Camera_velocity = new_vel;
4935 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4937 vm_vec_add2( &Camera_pos, &delta_pos );
4939 float ot = Camera_time+0.0f;
4941 Camera_time += flFrametime;
4943 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4946 tmp.xyz.z = 4.739f; // always go this fast forward.
4948 // pick x and y velocities so they are always on a
4949 // circle with a 25 m radius.
4951 float tmp_angle = frand()*PI2;
4953 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4954 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4956 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4958 //mprintf(( "Changing velocity!\n" ));
4959 camera_set_velocity( &tmp, 0 );
4962 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4963 vector tmp = { 0.0f, 0.0f, 0.0f };
4964 camera_set_velocity( &tmp, 0 );
4969 void end_demo_campaign_do()
4971 #if defined(FS2_DEMO)
4972 // show upsell screens
4973 demo_upsell_show_screens();
4974 #elif defined(OEM_BUILD)
4975 // show oem upsell screens
4976 oem_upsell_show_screens();
4979 // drop into main hall
4980 gameseq_post_event( GS_EVENT_MAIN_MENU );
4983 // All code to process events. This is the only place
4984 // that you should change the state of the game.
4985 void game_process_event( int current_state, int event )
4987 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4990 case GS_EVENT_SIMULATOR_ROOM:
4991 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4994 case GS_EVENT_MAIN_MENU:
4995 gameseq_set_state(GS_STATE_MAIN_MENU);
4998 case GS_EVENT_OPTIONS_MENU:
4999 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5002 case GS_EVENT_BARRACKS_MENU:
5003 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5006 case GS_EVENT_TECH_MENU:
5007 gameseq_set_state(GS_STATE_TECH_MENU);
5010 case GS_EVENT_TRAINING_MENU:
5011 gameseq_set_state(GS_STATE_TRAINING_MENU);
5014 case GS_EVENT_START_GAME:
5015 Select_default_ship = 0;
5016 Player_multi_died_check = -1;
5017 gameseq_set_state(GS_STATE_CMD_BRIEF);
5020 case GS_EVENT_START_BRIEFING:
5021 gameseq_set_state(GS_STATE_BRIEFING);
5024 case GS_EVENT_DEBRIEF:
5025 // did we end the campaign in the main freespace 2 single player campaign?
5026 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5027 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5029 gameseq_set_state(GS_STATE_DEBRIEF);
5032 Player_multi_died_check = -1;
5035 case GS_EVENT_SHIP_SELECTION:
5036 gameseq_set_state( GS_STATE_SHIP_SELECT );
5039 case GS_EVENT_WEAPON_SELECTION:
5040 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5043 case GS_EVENT_ENTER_GAME:
5045 // maybe start recording a demo
5047 demo_start_record("test.fsd");
5051 if (Game_mode & GM_MULTIPLAYER) {
5052 // if we're respawning, make sure we change the view mode so that the hud shows up
5053 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5057 gameseq_set_state(GS_STATE_GAME_PLAY);
5059 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5062 Player_multi_died_check = -1;
5064 // clear multiplayer button info
5065 extern button_info Multi_ship_status_bi;
5066 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5068 Start_time = f2fl(timer_get_approx_seconds());
5070 mprintf(("Entering game at time = %7.3f\n", Start_time));
5074 case GS_EVENT_START_GAME_QUICK:
5075 Select_default_ship = 1;
5076 gameseq_post_event(GS_EVENT_ENTER_GAME);
5080 case GS_EVENT_END_GAME:
5081 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5082 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5083 gameseq_set_state(GS_STATE_MAIN_MENU);
5088 Player_multi_died_check = -1;
5091 case GS_EVENT_QUIT_GAME:
5092 main_hall_stop_music();
5093 main_hall_stop_ambient();
5094 gameseq_set_state(GS_STATE_QUIT_GAME);
5096 Player_multi_died_check = -1;
5099 case GS_EVENT_GAMEPLAY_HELP:
5100 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5103 case GS_EVENT_PAUSE_GAME:
5104 gameseq_push_state(GS_STATE_GAME_PAUSED);
5107 case GS_EVENT_DEBUG_PAUSE_GAME:
5108 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5111 case GS_EVENT_TRAINING_PAUSE:
5112 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5115 case GS_EVENT_PREVIOUS_STATE:
5116 gameseq_pop_state();
5119 case GS_EVENT_TOGGLE_FULLSCREEN:
5120 #ifndef HARDWARE_ONLY
5122 if ( gr_screen.mode == GR_SOFTWARE ) {
5123 gr_init( GR_640, GR_DIRECTDRAW );
5124 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5125 gr_init( GR_640, GR_SOFTWARE );
5131 case GS_EVENT_TOGGLE_GLIDE:
5133 if ( gr_screen.mode != GR_GLIDE ) {
5134 gr_init( GR_640, GR_GLIDE );
5136 gr_init( GR_640, GR_SOFTWARE );
5141 case GS_EVENT_LOAD_MISSION_MENU:
5142 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5145 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5146 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5149 case GS_EVENT_HUD_CONFIG:
5150 gameseq_push_state( GS_STATE_HUD_CONFIG );
5153 case GS_EVENT_CONTROL_CONFIG:
5154 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5157 case GS_EVENT_DEATH_DIED:
5158 gameseq_set_state( GS_STATE_DEATH_DIED );
5161 case GS_EVENT_DEATH_BLEW_UP:
5162 if ( current_state == GS_STATE_DEATH_DIED ) {
5163 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5164 event_music_player_death();
5166 // multiplayer clients set their extra check here
5167 if(Game_mode & GM_MULTIPLAYER){
5168 // set the multi died absolute last chance check
5169 Player_multi_died_check = time(NULL);
5172 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5176 case GS_EVENT_NEW_CAMPAIGN:
5177 if (!mission_load_up_campaign()){
5178 readyroom_continue_campaign();
5181 Player_multi_died_check = -1;
5184 case GS_EVENT_CAMPAIGN_CHEAT:
5185 if (!mission_load_up_campaign()){
5187 // bash campaign value
5188 extern char Main_hall_campaign_cheat[512];
5191 // look for the mission
5192 for(idx=0; idx<Campaign.num_missions; idx++){
5193 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5194 Campaign.next_mission = idx;
5195 Campaign.prev_mission = idx - 1;
5202 readyroom_continue_campaign();
5205 Player_multi_died_check = -1;
5208 case GS_EVENT_CAMPAIGN_ROOM:
5209 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5212 case GS_EVENT_CMD_BRIEF:
5213 gameseq_set_state(GS_STATE_CMD_BRIEF);
5216 case GS_EVENT_RED_ALERT:
5217 gameseq_set_state(GS_STATE_RED_ALERT);
5220 case GS_EVENT_CREDITS:
5221 gameseq_set_state( GS_STATE_CREDITS );
5224 case GS_EVENT_VIEW_MEDALS:
5225 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5228 case GS_EVENT_SHOW_GOALS:
5229 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5232 case GS_EVENT_HOTKEY_SCREEN:
5233 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5236 // multiplayer stuff follow these comments
5238 case GS_EVENT_MULTI_JOIN_GAME:
5239 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5242 case GS_EVENT_MULTI_HOST_SETUP:
5243 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5246 case GS_EVENT_MULTI_CLIENT_SETUP:
5247 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5250 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5251 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5254 case GS_EVENT_MULTI_STD_WAIT:
5255 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5258 case GS_EVENT_STANDALONE_MAIN:
5259 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5262 case GS_EVENT_MULTI_PAUSE:
5263 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5266 case GS_EVENT_INGAME_PRE_JOIN:
5267 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5270 case GS_EVENT_EVENT_DEBUG:
5271 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5274 // Start a warpout where player automatically goes 70 no matter what
5275 // and can't cancel out of it.
5276 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5277 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5279 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5280 Player->saved_viewer_mode = Viewer_mode;
5281 Player->control_mode = PCM_WARPOUT_STAGE1;
5282 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5283 Warpout_time = 0.0f; // Start timer!
5286 case GS_EVENT_PLAYER_WARPOUT_START:
5287 if ( Player->control_mode != PCM_NORMAL ) {
5288 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5290 Player->saved_viewer_mode = Viewer_mode;
5291 Player->control_mode = PCM_WARPOUT_STAGE1;
5292 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5293 Warpout_time = 0.0f; // Start timer!
5294 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5298 case GS_EVENT_PLAYER_WARPOUT_STOP:
5299 if ( Player->control_mode != PCM_NORMAL ) {
5300 if ( !Warpout_forced ) { // cannot cancel forced warpout
5301 Player->control_mode = PCM_NORMAL;
5302 Viewer_mode = Player->saved_viewer_mode;
5303 hud_subspace_notify_abort();
5304 mprintf(( "Player put back to normal mode.\n" ));
5305 if ( Warpout_sound > -1 ) {
5306 snd_stop( Warpout_sound );
5313 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5314 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5315 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5316 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5318 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5319 shipfx_warpout_start( Player_obj );
5320 Player->control_mode = PCM_WARPOUT_STAGE2;
5321 Player->saved_viewer_mode = Viewer_mode;
5322 Viewer_mode |= VM_WARP_CHASE;
5324 vector tmp = Player_obj->pos;
5326 ship_get_eye( &tmp, &tmp_m, Player_obj );
5327 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5328 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5329 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5331 camera_set_position( &tmp );
5332 camera_set_orient( &Player_obj->orient );
5333 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5335 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5336 camera_set_velocity( &tmp_vel, 1);
5340 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5341 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5342 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5343 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5345 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5346 Player->control_mode = PCM_WARPOUT_STAGE3;
5350 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5351 mprintf(( "Player warped out. Going to debriefing!\n" ));
5352 Player->control_mode = PCM_NORMAL;
5353 Viewer_mode = Player->saved_viewer_mode;
5356 // we have a special debriefing screen for multiplayer furballs
5357 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5358 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5360 // do the normal debriefing for all other situations
5362 gameseq_post_event(GS_EVENT_DEBRIEF);
5366 case GS_EVENT_STANDALONE_POSTGAME:
5367 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5370 case GS_EVENT_INITIAL_PLAYER_SELECT:
5371 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5374 case GS_EVENT_GAME_INIT:
5375 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5376 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5378 // see if the command line option has been set to use the last pilot, and act acoordingly
5379 if( player_select_get_last_pilot() ) {
5380 // always enter the main menu -- do the automatic network startup stuff elsewhere
5381 // so that we still have valid checks for networking modes, etc.
5382 gameseq_set_state(GS_STATE_MAIN_MENU);
5384 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5389 case GS_EVENT_MULTI_MISSION_SYNC:
5390 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5393 case GS_EVENT_MULTI_START_GAME:
5394 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5397 case GS_EVENT_MULTI_HOST_OPTIONS:
5398 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5401 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5402 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5405 case GS_EVENT_TEAM_SELECT:
5406 gameseq_set_state(GS_STATE_TEAM_SELECT);
5409 case GS_EVENT_END_CAMPAIGN:
5410 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5413 case GS_EVENT_END_DEMO:
5414 gameseq_set_state(GS_STATE_END_DEMO);
5417 case GS_EVENT_LOOP_BRIEF:
5418 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5427 // Called when a state is being left.
5428 // The current state is still at old_state, but as soon as
5429 // this function leaves, then the current state will become
5430 // new state. You should never try to change the state
5431 // in here... if you think you need to, you probably really
5432 // need to post an event, not change the state.
5433 void game_leave_state( int old_state, int new_state )
5435 int end_mission = 1;
5437 switch (new_state) {
5438 case GS_STATE_GAME_PAUSED:
5439 case GS_STATE_DEBUG_PAUSED:
5440 case GS_STATE_OPTIONS_MENU:
5441 case GS_STATE_CONTROL_CONFIG:
5442 case GS_STATE_MISSION_LOG_SCROLLBACK:
5443 case GS_STATE_DEATH_DIED:
5444 case GS_STATE_SHOW_GOALS:
5445 case GS_STATE_HOTKEY_SCREEN:
5446 case GS_STATE_MULTI_PAUSED:
5447 case GS_STATE_TRAINING_PAUSED:
5448 case GS_STATE_EVENT_DEBUG:
5449 case GS_STATE_GAMEPLAY_HELP:
5450 end_mission = 0; // these events shouldn't end a mission
5454 switch (old_state) {
5455 case GS_STATE_BRIEFING:
5456 brief_stop_voices();
5457 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5458 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5459 && (new_state != GS_STATE_TEAM_SELECT) ){
5460 common_select_close();
5461 if ( new_state == GS_STATE_MAIN_MENU ) {
5462 freespace_stop_mission();
5466 // COMMAND LINE OPTION
5467 if (Cmdline_multi_stream_chat_to_file){
5468 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5469 cfclose(Multi_chat_stream);
5473 case GS_STATE_DEBRIEF:
5474 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5479 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5480 multi_df_debrief_close();
5483 case GS_STATE_LOAD_MISSION_MENU:
5484 mission_load_menu_close();
5487 case GS_STATE_SIMULATOR_ROOM:
5491 case GS_STATE_CAMPAIGN_ROOM:
5492 campaign_room_close();
5495 case GS_STATE_CMD_BRIEF:
5496 if (new_state == GS_STATE_OPTIONS_MENU) {
5501 if (new_state == GS_STATE_MAIN_MENU)
5502 freespace_stop_mission();
5507 case GS_STATE_RED_ALERT:
5511 case GS_STATE_SHIP_SELECT:
5512 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5513 new_state != GS_STATE_HOTKEY_SCREEN &&
5514 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5515 common_select_close();
5516 if ( new_state == GS_STATE_MAIN_MENU ) {
5517 freespace_stop_mission();
5522 case GS_STATE_WEAPON_SELECT:
5523 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5524 new_state != GS_STATE_HOTKEY_SCREEN &&
5525 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5526 common_select_close();
5527 if ( new_state == GS_STATE_MAIN_MENU ) {
5528 freespace_stop_mission();
5533 case GS_STATE_TEAM_SELECT:
5534 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5535 new_state != GS_STATE_HOTKEY_SCREEN &&
5536 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5537 common_select_close();
5538 if ( new_state == GS_STATE_MAIN_MENU ) {
5539 freespace_stop_mission();
5544 case GS_STATE_MAIN_MENU:
5545 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5552 case GS_STATE_OPTIONS_MENU:
5553 //game_start_time();
5554 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5555 multi_join_clear_game_list();
5557 options_menu_close();
5560 case GS_STATE_BARRACKS_MENU:
5561 if(new_state != GS_STATE_VIEW_MEDALS){
5566 case GS_STATE_MISSION_LOG_SCROLLBACK:
5567 hud_scrollback_close();
5570 case GS_STATE_TRAINING_MENU:
5571 training_menu_close();
5574 case GS_STATE_GAME_PLAY:
5575 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5576 player_save_target_and_weapon_link_prefs();
5577 game_stop_looped_sounds();
5580 sound_env_disable();
5581 joy_ff_stop_effects();
5583 // stop game time under certain conditions
5584 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5589 // shut down any recording or playing demos
5594 // when in multiplayer and going back to the main menu, send a leave game packet
5595 // right away (before calling stop mission). stop_mission was taking to long to
5596 // close mission down and I want people to get notified ASAP.
5597 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5598 multi_quit_game(PROMPT_NONE);
5601 freespace_stop_mission();
5602 Game_time_compression = F1_0;
5606 case GS_STATE_TECH_MENU:
5610 case GS_STATE_TRAINING_PAUSED:
5611 Training_num_lines = 0;
5612 // fall through to GS_STATE_GAME_PAUSED
5614 case GS_STATE_GAME_PAUSED:
5616 if ( end_mission ) {
5621 case GS_STATE_DEBUG_PAUSED:
5624 pause_debug_close();
5628 case GS_STATE_HUD_CONFIG:
5632 // join/start a game
5633 case GS_STATE_MULTI_JOIN_GAME:
5634 if(new_state != GS_STATE_OPTIONS_MENU){
5635 multi_join_game_close();
5639 case GS_STATE_MULTI_HOST_SETUP:
5640 case GS_STATE_MULTI_CLIENT_SETUP:
5641 // if this is just the host going into the options screen, don't do anything
5642 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5646 // close down the proper state
5647 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5648 multi_create_game_close();
5650 multi_game_client_setup_close();
5653 // COMMAND LINE OPTION
5654 if (Cmdline_multi_stream_chat_to_file){
5655 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5656 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5657 cfclose(Multi_chat_stream);
5662 case GS_STATE_CONTROL_CONFIG:
5663 control_config_close();
5666 case GS_STATE_DEATH_DIED:
5667 Game_mode &= ~GM_DEAD_DIED;
5669 // early end while respawning or blowing up in a multiplayer game
5670 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5672 freespace_stop_mission();
5676 case GS_STATE_DEATH_BLEW_UP:
5677 Game_mode &= ~GM_DEAD_BLEW_UP;
5679 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5680 // to determine if I should do anything.
5681 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5683 freespace_stop_mission();
5686 // if we are not respawing as an observer or as a player, our new state will not
5687 // be gameplay state.
5688 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5689 game_stop_time(); // hasn't been called yet!!
5690 freespace_stop_mission();
5696 case GS_STATE_CREDITS:
5700 case GS_STATE_VIEW_MEDALS:
5704 case GS_STATE_SHOW_GOALS:
5705 mission_show_goals_close();
5708 case GS_STATE_HOTKEY_SCREEN:
5709 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5710 mission_hotkey_close();
5714 case GS_STATE_MULTI_MISSION_SYNC:
5715 // if we're moving into the options menu, don't do anything
5716 if(new_state == GS_STATE_OPTIONS_MENU){
5720 Assert( Game_mode & GM_MULTIPLAYER );
5722 if ( new_state == GS_STATE_GAME_PLAY ){
5723 // palette_restore_palette();
5725 // change a couple of flags to indicate our state!!!
5726 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5727 send_netplayer_update_packet();
5729 // set the game mode
5730 Game_mode |= GM_IN_MISSION;
5734 case GS_STATE_VIEW_CUTSCENES:
5735 cutscenes_screen_close();
5738 case GS_STATE_MULTI_STD_WAIT:
5739 multi_standalone_wait_close();
5742 case GS_STATE_STANDALONE_MAIN:
5743 standalone_main_close();
5744 if(new_state == GS_STATE_MULTI_STD_WAIT){
5745 init_multiplayer_stats();
5749 case GS_STATE_MULTI_PAUSED:
5750 // if ( end_mission ){
5755 case GS_STATE_INGAME_PRE_JOIN:
5756 multi_ingame_select_close();
5759 case GS_STATE_STANDALONE_POSTGAME:
5760 multi_standalone_postgame_close();
5763 case GS_STATE_INITIAL_PLAYER_SELECT:
5764 player_select_close();
5767 case GS_STATE_MULTI_START_GAME:
5768 multi_start_game_close();
5771 case GS_STATE_MULTI_HOST_OPTIONS:
5772 multi_host_options_close();
5775 case GS_STATE_END_OF_CAMPAIGN:
5776 mission_campaign_end_close();
5779 case GS_STATE_LOOP_BRIEF:
5785 // Called when a state is being entered.
5786 // The current state is set to the state we're entering at
5787 // this point, and old_state is set to the state we're coming
5788 // from. You should never try to change the state
5789 // in here... if you think you need to, you probably really
5790 // need to post an event, not change the state.
5792 void game_enter_state( int old_state, int new_state )
5794 switch (new_state) {
5795 case GS_STATE_MAIN_MENU:
5796 // in multiplayer mode, be sure that we are not doing networking anymore.
5797 if ( Game_mode & GM_MULTIPLAYER ) {
5798 Assert( Net_player != NULL );
5799 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5802 Game_time_compression = F1_0;
5804 // determine which ship this guy is currently based on
5805 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5808 if (Player->on_bastion) {
5816 case GS_STATE_BRIEFING:
5817 main_hall_stop_music();
5818 main_hall_stop_ambient();
5820 if (Game_mode & GM_NORMAL) {
5821 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5822 // MWA: or from options or hotkey screens
5823 // JH: or if the command brief state already did this
5824 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5825 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5826 && (old_state != GS_STATE_CMD_BRIEF) ) {
5827 if ( !game_start_mission() ) // this should put us into a new state on failure!
5831 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5832 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5833 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5835 Game_time_compression = F1_0;
5837 if ( red_alert_mission() ) {
5838 gameseq_post_event(GS_EVENT_RED_ALERT);
5845 case GS_STATE_DEBRIEF:
5846 game_stop_looped_sounds();
5847 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5848 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5853 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5854 multi_df_debrief_init();
5857 case GS_STATE_LOAD_MISSION_MENU:
5858 mission_load_menu_init();
5861 case GS_STATE_SIMULATOR_ROOM:
5865 case GS_STATE_CAMPAIGN_ROOM:
5866 campaign_room_init();
5869 case GS_STATE_RED_ALERT:
5870 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5874 case GS_STATE_CMD_BRIEF: {
5875 int team_num = 0; // team number used as index for which cmd brief to use.
5877 if (old_state == GS_STATE_OPTIONS_MENU) {
5881 main_hall_stop_music();
5882 main_hall_stop_ambient();
5884 if (Game_mode & GM_NORMAL) {
5885 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5886 // MWA: or from options or hotkey screens
5887 // JH: or if the command brief state already did this
5888 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5889 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5890 if ( !game_start_mission() ) // this should put us into a new state on failure!
5895 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5896 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5897 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5899 cmd_brief_init(team_num);
5905 case GS_STATE_SHIP_SELECT:
5909 case GS_STATE_WEAPON_SELECT:
5910 weapon_select_init();
5913 case GS_STATE_TEAM_SELECT:
5917 case GS_STATE_GAME_PAUSED:
5922 case GS_STATE_DEBUG_PAUSED:
5923 // game_stop_time();
5924 // os_set_title("FreeSpace - PAUSED");
5927 case GS_STATE_TRAINING_PAUSED:
5934 case GS_STATE_OPTIONS_MENU:
5936 options_menu_init();
5939 case GS_STATE_GAME_PLAY:
5940 // coming from the gameplay state or the main menu, we might need to load the mission
5941 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5942 if ( !game_start_mission() ) // this should put us into a new state.
5947 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5948 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5949 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5950 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5951 (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) ) {
5952 // JAS: Used to do all paging here.
5956 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5960 main_hall_stop_music();
5961 main_hall_stop_ambient();
5962 event_music_first_pattern(); // start the first pattern
5965 // special code that restores player ship selection and weapons loadout when doing a quick start
5966 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5967 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5968 wss_direct_restore_loadout();
5972 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5973 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5974 event_music_first_pattern(); // start the first pattern
5977 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5978 event_music_first_pattern(); // start the first pattern
5980 player_restore_target_and_weapon_link_prefs();
5982 Game_mode |= GM_IN_MISSION;
5985 // required to truely make mouse deltas zeroed in debug mouse code
5986 void mouse_force_pos(int x, int y);
5987 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5992 // only start time if in single player, or coming from multi wait state
5995 (Game_mode & GM_NORMAL) &&
5996 (old_state != GS_STATE_VIEW_CUTSCENES)
5998 (Game_mode & GM_MULTIPLAYER) && (
5999 (old_state == GS_STATE_MULTI_PAUSED) ||
6000 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6006 // when coming from the multi paused state, reset the timestamps
6007 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6008 multi_reset_timestamps();
6011 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6012 // initialize all object update details
6013 multi_oo_gameplay_init();
6016 // under certain circumstances, the server should reset the object update rate limiting stuff
6017 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6018 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6020 // reinitialize the rate limiting system for all clients
6021 multi_oo_rate_init_all();
6024 // multiplayer clients should always re-initialize their control info rate limiting system
6025 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6026 multi_oo_rate_init_all();
6030 if(Game_mode & GM_MULTIPLAYER){
6031 multi_ping_reset_players();
6034 Game_subspace_effect = 0;
6035 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6036 Game_subspace_effect = 1;
6037 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6038 game_start_subspace_ambient_sound();
6042 sound_env_set(&Game_sound_env);
6043 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6045 // clear multiplayer button info i
6046 extern button_info Multi_ship_status_bi;
6047 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6050 case GS_STATE_HUD_CONFIG:
6054 case GS_STATE_MULTI_JOIN_GAME:
6055 multi_join_clear_game_list();
6057 if (old_state != GS_STATE_OPTIONS_MENU) {
6058 multi_join_game_init();
6063 case GS_STATE_MULTI_HOST_SETUP:
6064 // don't reinitialize if we're coming back from the host options screen
6065 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6066 multi_create_game_init();
6071 case GS_STATE_MULTI_CLIENT_SETUP:
6072 if (old_state != GS_STATE_OPTIONS_MENU) {
6073 multi_game_client_setup_init();
6078 case GS_STATE_CONTROL_CONFIG:
6079 control_config_init();
6082 case GS_STATE_TECH_MENU:
6086 case GS_STATE_BARRACKS_MENU:
6087 if(old_state != GS_STATE_VIEW_MEDALS){
6092 case GS_STATE_MISSION_LOG_SCROLLBACK:
6093 hud_scrollback_init();
6096 case GS_STATE_DEATH_DIED:
6097 Player_died_time = timestamp(10);
6099 if(!(Game_mode & GM_MULTIPLAYER)){
6100 player_show_death_message();
6102 Game_mode |= GM_DEAD_DIED;
6105 case GS_STATE_DEATH_BLEW_UP:
6106 if ( !popupdead_is_active() ) {
6107 Player_ai->target_objnum = -1;
6110 // stop any local EMP effect
6113 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6114 Game_mode |= GM_DEAD_BLEW_UP;
6115 Show_viewing_from_self = 0;
6117 // timestamp how long we should wait before displaying the died popup
6118 if ( !popupdead_is_active() ) {
6119 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6123 case GS_STATE_GAMEPLAY_HELP:
6124 gameplay_help_init();
6127 case GS_STATE_CREDITS:
6128 main_hall_stop_music();
6129 main_hall_stop_ambient();
6133 case GS_STATE_VIEW_MEDALS:
6134 medal_main_init(Player);
6137 case GS_STATE_SHOW_GOALS:
6138 mission_show_goals_init();
6141 case GS_STATE_HOTKEY_SCREEN:
6142 mission_hotkey_init();
6145 case GS_STATE_MULTI_MISSION_SYNC:
6146 // if we're coming from the options screen, don't do any
6147 if(old_state == GS_STATE_OPTIONS_MENU){
6151 switch(Multi_sync_mode){
6152 case MULTI_SYNC_PRE_BRIEFING:
6153 // if moving from game forming to the team select state
6156 case MULTI_SYNC_POST_BRIEFING:
6157 // if moving from briefing into the mission itself
6160 // tell everyone that we're now loading data
6161 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6162 send_netplayer_update_packet();
6164 // JAS: Used to do all paging here!!!!
6166 Net_player->state = NETPLAYER_STATE_WAITING;
6167 send_netplayer_update_packet();
6169 Game_time_compression = F1_0;
6171 case MULTI_SYNC_INGAME:
6177 case GS_STATE_VIEW_CUTSCENES:
6178 cutscenes_screen_init();
6181 case GS_STATE_MULTI_STD_WAIT:
6182 multi_standalone_wait_init();
6185 case GS_STATE_STANDALONE_MAIN:
6186 // don't initialize if we're coming from one of these 2 states unless there are no
6187 // players left (reset situation)
6188 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6189 standalone_main_init();
6193 case GS_STATE_MULTI_PAUSED:
6197 case GS_STATE_INGAME_PRE_JOIN:
6198 multi_ingame_select_init();
6201 case GS_STATE_STANDALONE_POSTGAME:
6202 multi_standalone_postgame_init();
6205 case GS_STATE_INITIAL_PLAYER_SELECT:
6206 player_select_init();
6209 case GS_STATE_MULTI_START_GAME:
6210 multi_start_game_init();
6213 case GS_STATE_MULTI_HOST_OPTIONS:
6214 multi_host_options_init();
6217 case GS_STATE_END_OF_CAMPAIGN:
6218 mission_campaign_end_init();
6221 case GS_STATE_LOOP_BRIEF:
6228 // do stuff that may need to be done regardless of state
6229 void game_do_state_common(int state,int no_networking)
6231 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6232 snd_do_frame(); // update sound system
6233 event_music_do_frame(); // music needs to play across many states
6235 multi_log_process();
6237 if (no_networking) {
6241 // maybe do a multiplayer frame based on game mode and state type
6242 if (Game_mode & GM_MULTIPLAYER) {
6244 case GS_STATE_OPTIONS_MENU:
6245 case GS_STATE_GAMEPLAY_HELP:
6246 case GS_STATE_HOTKEY_SCREEN:
6247 case GS_STATE_HUD_CONFIG:
6248 case GS_STATE_CONTROL_CONFIG:
6249 case GS_STATE_MISSION_LOG_SCROLLBACK:
6250 case GS_STATE_SHOW_GOALS:
6251 case GS_STATE_VIEW_CUTSCENES:
6252 case GS_STATE_EVENT_DEBUG:
6253 multi_maybe_do_frame();
6257 game_do_networking();
6261 // Called once a frame.
6262 // You should never try to change the state
6263 // in here... if you think you need to, you probably really
6264 // need to post an event, not change the state.
6265 int Game_do_state_should_skip = 0;
6266 void game_do_state(int state)
6268 // always lets the do_state_common() function determine if the state should be skipped
6269 Game_do_state_should_skip = 0;
6271 // legal to set the should skip state anywhere in this function
6272 game_do_state_common(state); // do stuff that may need to be done regardless of state
6274 if(Game_do_state_should_skip){
6279 case GS_STATE_MAIN_MENU:
6280 game_set_frametime(GS_STATE_MAIN_MENU);
6281 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6284 main_hall_do(flFrametime);
6288 case GS_STATE_OPTIONS_MENU:
6289 game_set_frametime(GS_STATE_OPTIONS_MENU);
6290 options_menu_do_frame(flFrametime);
6293 case GS_STATE_BARRACKS_MENU:
6294 game_set_frametime(GS_STATE_BARRACKS_MENU);
6295 barracks_do_frame(flFrametime);
6298 case GS_STATE_TRAINING_MENU:
6299 game_set_frametime(GS_STATE_TRAINING_MENU);
6300 training_menu_do_frame(flFrametime);
6303 case GS_STATE_TECH_MENU:
6304 game_set_frametime(GS_STATE_TECH_MENU);
6305 techroom_do_frame(flFrametime);
6308 case GS_STATE_GAMEPLAY_HELP:
6309 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6310 gameplay_help_do_frame(flFrametime);
6313 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6317 case GS_STATE_GAME_PAUSED:
6321 case GS_STATE_DEBUG_PAUSED:
6323 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6328 case GS_STATE_TRAINING_PAUSED:
6329 game_training_pause_do();
6332 case GS_STATE_LOAD_MISSION_MENU:
6333 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6334 mission_load_menu_do();
6337 case GS_STATE_BRIEFING:
6338 game_set_frametime(GS_STATE_BRIEFING);
6339 brief_do_frame(flFrametime);
6342 case GS_STATE_DEBRIEF:
6343 game_set_frametime(GS_STATE_DEBRIEF);
6344 debrief_do_frame(flFrametime);
6347 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6348 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6349 multi_df_debrief_do();
6352 case GS_STATE_SHIP_SELECT:
6353 game_set_frametime(GS_STATE_SHIP_SELECT);
6354 ship_select_do(flFrametime);
6357 case GS_STATE_WEAPON_SELECT:
6358 game_set_frametime(GS_STATE_WEAPON_SELECT);
6359 weapon_select_do(flFrametime);
6362 case GS_STATE_MISSION_LOG_SCROLLBACK:
6363 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6364 hud_scrollback_do_frame(flFrametime);
6367 case GS_STATE_HUD_CONFIG:
6368 game_set_frametime(GS_STATE_HUD_CONFIG);
6369 hud_config_do_frame(flFrametime);
6372 case GS_STATE_MULTI_JOIN_GAME:
6373 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6374 multi_join_game_do_frame();
6377 case GS_STATE_MULTI_HOST_SETUP:
6378 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6379 multi_create_game_do();
6382 case GS_STATE_MULTI_CLIENT_SETUP:
6383 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6384 multi_game_client_setup_do_frame();
6387 case GS_STATE_CONTROL_CONFIG:
6388 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6389 control_config_do_frame(flFrametime);
6392 case GS_STATE_DEATH_DIED:
6396 case GS_STATE_DEATH_BLEW_UP:
6400 case GS_STATE_SIMULATOR_ROOM:
6401 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6402 sim_room_do_frame(flFrametime);
6405 case GS_STATE_CAMPAIGN_ROOM:
6406 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6407 campaign_room_do_frame(flFrametime);
6410 case GS_STATE_RED_ALERT:
6411 game_set_frametime(GS_STATE_RED_ALERT);
6412 red_alert_do_frame(flFrametime);
6415 case GS_STATE_CMD_BRIEF:
6416 game_set_frametime(GS_STATE_CMD_BRIEF);
6417 cmd_brief_do_frame(flFrametime);
6420 case GS_STATE_CREDITS:
6421 game_set_frametime(GS_STATE_CREDITS);
6422 credits_do_frame(flFrametime);
6425 case GS_STATE_VIEW_MEDALS:
6426 game_set_frametime(GS_STATE_VIEW_MEDALS);
6430 case GS_STATE_SHOW_GOALS:
6431 game_set_frametime(GS_STATE_SHOW_GOALS);
6432 mission_show_goals_do_frame(flFrametime);
6435 case GS_STATE_HOTKEY_SCREEN:
6436 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6437 mission_hotkey_do_frame(flFrametime);
6440 case GS_STATE_VIEW_CUTSCENES:
6441 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6442 cutscenes_screen_do_frame();
6445 case GS_STATE_MULTI_STD_WAIT:
6446 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6447 multi_standalone_wait_do();
6450 case GS_STATE_STANDALONE_MAIN:
6451 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6452 standalone_main_do();
6455 case GS_STATE_MULTI_PAUSED:
6456 game_set_frametime(GS_STATE_MULTI_PAUSED);
6460 case GS_STATE_TEAM_SELECT:
6461 game_set_frametime(GS_STATE_TEAM_SELECT);
6465 case GS_STATE_INGAME_PRE_JOIN:
6466 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6467 multi_ingame_select_do();
6470 case GS_STATE_EVENT_DEBUG:
6472 game_set_frametime(GS_STATE_EVENT_DEBUG);
6473 game_show_event_debug(flFrametime);
6477 case GS_STATE_STANDALONE_POSTGAME:
6478 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6479 multi_standalone_postgame_do();
6482 case GS_STATE_INITIAL_PLAYER_SELECT:
6483 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6487 case GS_STATE_MULTI_MISSION_SYNC:
6488 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6492 case GS_STATE_MULTI_START_GAME:
6493 game_set_frametime(GS_STATE_MULTI_START_GAME);
6494 multi_start_game_do();
6497 case GS_STATE_MULTI_HOST_OPTIONS:
6498 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6499 multi_host_options_do();
6502 case GS_STATE_END_OF_CAMPAIGN:
6503 mission_campaign_end_do();
6506 case GS_STATE_END_DEMO:
6507 game_set_frametime(GS_STATE_END_DEMO);
6508 end_demo_campaign_do();
6511 case GS_STATE_LOOP_BRIEF:
6512 game_set_frametime(GS_STATE_LOOP_BRIEF);
6516 } // end switch(gs_current_state)
6520 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6521 int game_do_ram_check(int ram_in_bytes)
6523 if ( ram_in_bytes < 30*1024*1024 ) {
6524 int allowed_to_run = 1;
6525 if ( ram_in_bytes < 25*1024*1024 ) {
6530 int Freespace_total_ram_MB;
6531 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6533 if ( allowed_to_run ) {
6535 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);
6540 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6541 if ( msgbox_rval == IDCANCEL ) {
6548 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);
6550 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6561 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6562 // If so, copy it over and remove the update directory.
6563 void game_maybe_update_launcher(char *exe_dir)
6566 char src_filename[MAX_PATH];
6567 char dest_filename[MAX_PATH];
6569 strcpy(src_filename, exe_dir);
6570 strcat(src_filename, NOX("\\update\\freespace.exe"));
6572 strcpy(dest_filename, exe_dir);
6573 strcat(dest_filename, NOX("\\freespace.exe"));
6575 // see if src_filename exists
6577 fp = fopen(src_filename, "rb");
6583 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6585 // copy updated freespace.exe to freespace exe dir
6586 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6587 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 );
6591 // delete the file in the update directory
6592 DeleteFile(src_filename);
6594 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6595 char update_dir[MAX_PATH];
6596 strcpy(update_dir, exe_dir);
6597 strcat(update_dir, NOX("\\update"));
6598 RemoveDirectory(update_dir);
6604 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6608 int sub_total_destroyed = 0;
6612 // get the total for all his children
6613 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6614 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6617 // find the # of faces for this _individual_ object
6618 total = submodel_get_num_polys(model_num, sm);
6619 if(strstr(pm->submodel[sm].name, "-destroyed")){
6620 sub_total_destroyed = total;
6624 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6627 *out_total += total + sub_total;
6628 *out_destroyed_total += sub_total_destroyed;
6631 #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);
6632 void game_spew_pof_info()
6634 char *pof_list[1000];
6637 int idx, model_num, i, j;
6639 int total, root_total, model_total, destroyed_total, counted;
6643 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6645 // spew info on all the pofs
6651 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6656 for(idx=0; idx<num_files; idx++, counted++){
6657 sprintf(str, "%s.pof", pof_list[idx]);
6658 model_num = model_load(str, 0, NULL);
6660 pm = model_get(model_num);
6662 // if we have a real model
6667 // go through and print all raw submodels
6668 cfputs("RAW\n", out);
6671 for (i=0; i<pm->n_models; i++) {
6672 total = submodel_get_num_polys(model_num, i);
6674 model_total += total;
6675 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6678 sprintf(str, "Model total %d\n", model_total);
6681 // now go through and do it by LOD
6682 cfputs("BY LOD\n\n", out);
6683 for(i=0; i<pm->n_detail_levels; i++){
6684 sprintf(str, "LOD %d\n", i);
6688 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6690 destroyed_total = 0;
6691 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6692 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6695 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6698 sprintf(str, "TOTAL: %d\n", total + root_total);
6700 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6702 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6705 cfputs("------------------------------------------------------------------------\n\n", out);
6709 if(counted >= MAX_POLYGON_MODELS - 5){
6722 game_spew_pof_info();
6725 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6730 // Don't let more than one instance of Freespace run.
6731 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6733 SetForegroundWindow(hwnd);
6738 // Find out how much RAM is on this machine
6741 ms.dwLength = sizeof(MEMORYSTATUS);
6742 GlobalMemoryStatus(&ms);
6743 Freespace_total_ram = ms.dwTotalPhys;
6745 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6749 if ( ms.dwTotalVirtual < 1024 ) {
6750 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6754 if (!vm_init(24*1024*1024)) {
6755 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 );
6759 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6761 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);
6769 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6770 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6771 seem worth bothering with.
6775 lResult = RegOpenKeyEx(
6776 HKEY_LOCAL_MACHINE, // Where it is
6777 "Software\\Microsoft\\DirectX", // name of key
6778 NULL, // DWORD reserved
6779 KEY_QUERY_VALUE, // Allows all changes
6780 &hKey // Location to store key
6783 if (lResult == ERROR_SUCCESS) {
6785 DWORD dwType, dwLen;
6788 lResult = RegQueryValueEx(
6789 hKey, // Handle to key
6790 "Version", // The values name
6791 NULL, // DWORD reserved
6792 &dwType, // What kind it is
6793 (ubyte *) version, // value to set
6794 &dwLen // How many bytes to set
6797 if (lResult == ERROR_SUCCESS) {
6798 dx_version = atoi(strstr(version, ".") + 1);
6802 DWORD dwType, dwLen;
6805 lResult = RegQueryValueEx(
6806 hKey, // Handle to key
6807 "InstalledVersion", // The values name
6808 NULL, // DWORD reserved
6809 &dwType, // What kind it is
6810 (ubyte *) &val, // value to set
6811 &dwLen // How many bytes to set
6814 if (lResult == ERROR_SUCCESS) {
6822 if (dx_version < 3) {
6823 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6824 "latest version of DirectX at:\n\n"
6825 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6827 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6828 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6833 //=====================================================
6834 // Make sure we're running in the right directory.
6838 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6839 char *p = exe_dir + strlen(exe_dir);
6841 // chop off the filename
6842 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6848 if ( strlen(exe_dir) > 0 ) {
6849 SetCurrentDirectory(exe_dir);
6852 // check for updated freespace.exe
6853 game_maybe_update_launcher(exe_dir);
6861 extern void windebug_memwatch_init();
6862 windebug_memwatch_init();
6866 parse_cmdline(szCmdLine);
6868 #ifdef STANDALONE_ONLY_BUILD
6870 nprintf(("Network", "Standalone running"));
6873 nprintf(("Network", "Standalone running"));
6881 // maybe spew pof stuff
6882 if(Cmdline_spew_pof_info){
6883 game_spew_pof_info();
6888 // non-demo, non-standalone, play the intro movie
6893 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) ){
6895 #if defined(OEM_BUILD)
6896 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6898 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6899 #endif // defined(OEM_BUILD)
6904 if ( !Is_standalone ) {
6906 // release -- movies always play
6909 // 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
6910 movie_play( NOX("intro.mve"), 0 );
6912 // debug version, movie will only play with -showmovies
6913 #elif !defined(NDEBUG)
6915 movie_play( NOX("intro.mve"), 0);
6918 if ( Cmdline_show_movies )
6919 movie_play( NOX("intro.mve"), 0 );
6928 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6930 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6934 // only important for non THREADED mode
6937 state = gameseq_process_events();
6938 if ( state == GS_STATE_QUIT_GAME ){
6945 demo_upsell_show_screens();
6947 #elif defined(OEM_BUILD)
6948 // show upsell screens on exit
6949 oem_upsell_show_screens();
6956 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6962 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6964 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6966 // Do nothing here - RecordExceptionInfo() has already done
6967 // everything that is needed. Actually this code won't even
6968 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6969 // the __except clause.
6973 nprintf(("WinMain", "exceptions shall fall through"));
6975 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6981 // launcher the fslauncher program on exit
6982 void game_launch_launcher_on_exit()
6986 PROCESS_INFORMATION pi;
6987 char cmd_line[2048];
6988 char original_path[1024] = "";
6990 memset( &si, 0, sizeof(STARTUPINFO) );
6994 _getcwd(original_path, 1023);
6996 // set up command line
6997 strcpy(cmd_line, original_path);
6998 strcat(cmd_line, "\\");
6999 strcat(cmd_line, LAUNCHER_FNAME);
7000 strcat(cmd_line, " -straight_to_update");
7002 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7003 cmd_line, // pointer to command line string
7004 NULL, // pointer to process security attributes
7005 NULL, // pointer to thread security attributes
7006 FALSE, // handle inheritance flag
7007 CREATE_DEFAULT_ERROR_MODE, // creation flags
7008 NULL, // pointer to new environment block
7009 NULL, // pointer to current directory name
7010 &si, // pointer to STARTUPINFO
7011 &pi // pointer to PROCESS_INFORMATION
7013 // to eliminate build warnings
7023 // This function is called when FreeSpace terminates normally.
7025 void game_shutdown(void)
7031 // don't ever flip a page on the standalone!
7032 if(!(Game_mode & GM_STANDALONE_SERVER)){
7038 // if the player has left the "player select" screen and quit the game without actually choosing
7039 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7040 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7044 // load up common multiplayer icons
7045 multi_unload_common_icons();
7047 shockwave_close(); // release any memory used by shockwave system
7048 fireball_close(); // free fireball system
7049 ship_close(); // free any memory that was allocated for the ships
7050 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7051 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7052 bm_unload_all(); // free bitmaps
7053 mission_campaign_close(); // close out the campaign stuff
7054 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7056 #ifdef MULTI_USE_LAG
7060 // the menu close functions will unload the bitmaps if they were displayed during the game
7061 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7064 training_menu_close();
7067 extern void joy_close();
7070 audiostream_close();
7072 event_music_close();
7076 // HACKITY HACK HACK
7077 // if this flag is set, we should be firing up the launcher when exiting freespace
7078 extern int Multi_update_fireup_launcher_on_exit;
7079 if(Multi_update_fireup_launcher_on_exit){
7080 game_launch_launcher_on_exit();
7084 // game_stop_looped_sounds()
7086 // This function will call the appropriate stop looped sound functions for those
7087 // modules which use looping sounds. It is not enough just to stop a looping sound
7088 // at the DirectSound level, the game is keeping track of looping sounds, and this
7089 // function is used to inform the game that looping sounds are being halted.
7091 void game_stop_looped_sounds()
7093 hud_stop_looped_locking_sounds();
7094 hud_stop_looped_engine_sounds();
7095 afterburner_stop_sounds();
7096 player_stop_looped_sounds();
7097 obj_snd_stop_all(); // stop all object-linked persistant sounds
7098 game_stop_subspace_ambient_sound();
7099 snd_stop(Radar_static_looping);
7100 Radar_static_looping = -1;
7101 snd_stop(Target_static_looping);
7102 shipfx_stop_engine_wash_sound();
7103 Target_static_looping = -1;
7106 //////////////////////////////////////////////////////////////////////////
7108 // Code for supporting an animating mouse pointer
7111 //////////////////////////////////////////////////////////////////////////
7113 typedef struct animating_obj
7122 static animating_obj Animating_mouse;
7124 // ----------------------------------------------------------------------------
7125 // init_animating_pointer()
7127 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7128 // gets properly initialized
7130 void init_animating_pointer()
7132 Animating_mouse.first_frame = -1;
7133 Animating_mouse.num_frames = 0;
7134 Animating_mouse.current_frame = -1;
7135 Animating_mouse.time = 0.0f;
7136 Animating_mouse.elapsed_time = 0.0f;
7139 // ----------------------------------------------------------------------------
7140 // load_animating_pointer()
7142 // Called at game init to load in the frames for the animating mouse pointer
7144 // input: filename => filename of animation file that holds the animation
7146 void load_animating_pointer(char *filename, int dx, int dy)
7151 init_animating_pointer();
7153 am = &Animating_mouse;
7154 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7155 if ( am->first_frame == -1 )
7156 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7157 am->current_frame = 0;
7158 am->time = am->num_frames / i2fl(fps);
7161 // ----------------------------------------------------------------------------
7162 // unload_animating_pointer()
7164 // Called at game shutdown to free the memory used to store the animation frames
7166 void unload_animating_pointer()
7171 am = &Animating_mouse;
7172 for ( i = 0; i < am->num_frames; i++ ) {
7173 Assert( (am->first_frame+i) >= 0 );
7174 bm_release(am->first_frame + i);
7177 am->first_frame = -1;
7179 am->current_frame = -1;
7182 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7183 void game_render_mouse(float frametime)
7188 // if animating cursor exists, play the next frame
7189 am = &Animating_mouse;
7190 if ( am->first_frame != -1 ) {
7191 mouse_get_pos(&mx, &my);
7192 am->elapsed_time += frametime;
7193 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7194 if ( am->current_frame >= am->num_frames ) {
7195 am->current_frame = 0;
7196 am->elapsed_time = 0.0f;
7198 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7202 // ----------------------------------------------------------------------------
7203 // game_maybe_draw_mouse()
7205 // determines whether to draw the mouse pointer at all, and what frame of
7206 // animation to use if the mouse is animating
7208 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7210 // input: frametime => elapsed frame time in seconds since last call
7212 void game_maybe_draw_mouse(float frametime)
7216 game_state = gameseq_get_state();
7218 switch ( game_state ) {
7219 case GS_STATE_GAME_PAUSED:
7220 // case GS_STATE_MULTI_PAUSED:
7221 case GS_STATE_GAME_PLAY:
7222 case GS_STATE_DEATH_DIED:
7223 case GS_STATE_DEATH_BLEW_UP:
7224 if ( popup_active() || popupdead_is_active() ) {
7236 if ( !Mouse_hidden )
7237 game_render_mouse(frametime);
7241 void game_do_training_checks()
7245 waypoint_list *wplp;
7247 if (Training_context & TRAINING_CONTEXT_SPEED) {
7248 s = (int) Player_obj->phys_info.fspeed;
7249 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7250 if (!Training_context_speed_set) {
7251 Training_context_speed_set = 1;
7252 Training_context_speed_timestamp = timestamp();
7256 Training_context_speed_set = 0;
7259 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7260 wplp = &Waypoint_lists[Training_context_path];
7261 if (wplp->count > Training_context_goal_waypoint) {
7262 i = Training_context_goal_waypoint;
7264 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7265 if (d <= Training_context_distance) {
7266 Training_context_at_waypoint = i;
7267 if (Training_context_goal_waypoint == i) {
7268 Training_context_goal_waypoint++;
7269 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7276 if (i == wplp->count)
7279 } while (i != Training_context_goal_waypoint);
7283 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7284 Players_target = Player_ai->target_objnum;
7285 Players_targeted_subsys = Player_ai->targeted_subsys;
7286 Players_target_timestamp = timestamp();
7290 /////////// Following is for event debug view screen
7294 #define EVENT_DEBUG_MAX 5000
7295 #define EVENT_DEBUG_EVENT 0x8000
7297 int Event_debug_index[EVENT_DEBUG_MAX];
7300 void game_add_event_debug_index(int n, int indent)
7302 if (ED_count < EVENT_DEBUG_MAX)
7303 Event_debug_index[ED_count++] = n | (indent << 16);
7306 void game_add_event_debug_sexp(int n, int indent)
7311 if (Sexp_nodes[n].first >= 0) {
7312 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7313 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7317 game_add_event_debug_index(n, indent);
7318 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7319 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7321 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7324 void game_event_debug_init()
7329 for (e=0; e<Num_mission_events; e++) {
7330 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7331 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7335 void game_show_event_debug(float frametime)
7339 int font_height, font_width;
7341 static int scroll_offset = 0;
7343 k = game_check_key();
7349 if (scroll_offset < 0)
7359 scroll_offset -= 20;
7360 if (scroll_offset < 0)
7365 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7369 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7375 gr_set_color_fast(&Color_bright);
7377 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7379 gr_set_color_fast(&Color_normal);
7381 gr_get_string_size(&font_width, &font_height, NOX("test"));
7382 y_max = gr_screen.max_h - font_height - 5;
7386 while (k < ED_count) {
7387 if (y_index > y_max)
7390 z = Event_debug_index[k];
7391 if (z & EVENT_DEBUG_EVENT) {
7393 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7394 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7395 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7396 Mission_events[z].repeat_count, Mission_events[z].interval);
7404 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7405 switch (Sexp_nodes[z & 0x7fff].value) {
7407 strcat(buf, NOX(" (True)"));
7411 strcat(buf, NOX(" (False)"));
7414 case SEXP_KNOWN_TRUE:
7415 strcat(buf, NOX(" (Always true)"));
7418 case SEXP_KNOWN_FALSE:
7419 strcat(buf, NOX(" (Always false)"));
7422 case SEXP_CANT_EVAL:
7423 strcat(buf, NOX(" (Can't eval)"));
7427 case SEXP_NAN_FOREVER:
7428 strcat(buf, NOX(" (Not a number)"));
7433 gr_printf(10, y_index, buf);
7434 y_index += font_height;
7447 extern int Tmap_npixels;
7449 int Tmap_num_too_big = 0;
7450 int Num_models_needing_splitting = 0;
7452 void Time_model( int modelnum )
7454 // mprintf(( "Timing ship '%s'\n", si->name ));
7456 vector eye_pos, model_pos;
7457 matrix eye_orient, model_orient;
7459 polymodel *pm = model_get( modelnum );
7461 int l = strlen(pm->filename);
7463 if ( (l == '/') || (l=='\\') || (l==':')) {
7469 char *pof_file = &pm->filename[l];
7471 int model_needs_splitting = 0;
7473 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7475 for (i=0; i<pm->n_textures; i++ ) {
7476 char filename[1024];
7479 int bmp_num = pm->original_textures[i];
7480 if ( bmp_num > -1 ) {
7481 bm_get_palette(pm->original_textures[i], pal, filename );
7483 bm_get_info( pm->original_textures[i],&w, &h );
7486 if ( (w > 512) || (h > 512) ) {
7487 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7489 model_needs_splitting++;
7492 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7496 if ( model_needs_splitting ) {
7497 Num_models_needing_splitting++;
7499 eye_orient = model_orient = vmd_identity_matrix;
7500 eye_pos = model_pos = vmd_zero_vector;
7502 eye_pos.xyz.z = -pm->rad*2.0f;
7504 vector eye_to_model;
7506 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7507 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7509 fix t1 = timer_get_fixed_seconds();
7512 ta.p = ta.b = ta.h = 0.0f;
7517 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7519 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7521 modelstats_num_polys = modelstats_num_verts = 0;
7523 while( ta.h < PI2 ) {
7526 vm_angles_2_matrix(&m1, &ta );
7527 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7534 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7536 model_clear_instance( modelnum );
7537 model_set_detail_level(0); // use highest detail level
7538 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7546 int k = key_inkey();
7547 if ( k == KEY_ESC ) {
7552 fix t2 = timer_get_fixed_seconds();
7554 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7555 //bitmaps_used_this_frame /= framecount;
7557 modelstats_num_polys /= framecount;
7558 modelstats_num_verts /= framecount;
7560 Tmap_npixels /=framecount;
7563 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7564 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 );
7565 // 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 );
7571 int Time_models = 0;
7572 DCF_BOOL( time_models, Time_models );
7574 void Do_model_timings_test()
7578 if ( !Time_models ) return;
7580 mprintf(( "Timing models!\n" ));
7584 ubyte model_used[MAX_POLYGON_MODELS];
7585 int model_id[MAX_POLYGON_MODELS];
7586 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7591 for (i=0; i<Num_ship_types; i++ ) {
7592 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7594 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7595 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7598 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7599 if ( !Texture_fp ) return;
7601 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7602 if ( !Time_fp ) return;
7604 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7605 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7607 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7608 if ( model_used[i] ) {
7609 Time_model( model_id[i] );
7613 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7614 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7623 // Call this function when you want to inform the player that a feature is not
7624 // enabled in the DEMO version of FreSpace
7625 void game_feature_not_in_demo_popup()
7627 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7630 // format the specified time (fixed point) into a nice string
7631 void game_format_time(fix m_time,char *time_str)
7634 int hours,minutes,seconds;
7637 mtime = f2fl(m_time);
7639 // get the hours, minutes and seconds
7640 hours = (int)(mtime / 3600.0f);
7642 mtime -= (3600.0f * (float)hours);
7644 seconds = (int)mtime%60;
7645 minutes = (int)mtime/60;
7647 // print the hour if necessary
7649 sprintf(time_str,XSTR( "%d:", 201),hours);
7650 // if there are less than 10 minutes, print a leading 0
7652 strcpy(tmp,NOX("0"));
7653 strcat(time_str,tmp);
7657 // print the minutes
7659 sprintf(tmp,XSTR( "%d:", 201),minutes);
7660 strcat(time_str,tmp);
7662 sprintf(time_str,XSTR( "%d:", 201),minutes);
7665 // print the seconds
7667 strcpy(tmp,NOX("0"));
7668 strcat(time_str,tmp);
7670 sprintf(tmp,"%d",seconds);
7671 strcat(time_str,tmp);
7674 // Stuff version string in *str.
7675 void get_version_string(char *str)
7678 if ( FS_VERSION_BUILD == 0 ) {
7679 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7681 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7684 #if defined (FS2_DEMO)
7686 #elif defined (OEM_BUILD)
7687 strcat(str, " (OEM)");
7693 char myname[_MAX_PATH];
7694 int namelen, major, minor, build, waste;
7695 unsigned int buf_size;
7701 // Find my EXE file name
7702 hMod = GetModuleHandle(NULL);
7703 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7705 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7706 infop = (char *)malloc(version_size);
7707 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7709 // get the product version
7710 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7711 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7713 sprintf(str,"Dv%d.%02d",major, minor);
7715 sprintf(str,"v%d.%02d",major, minor);
7720 void get_version_string_short(char *str)
7722 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7725 // ----------------------------------------------------------------
7727 // OEM UPSELL SCREENS BEGIN
7729 // ----------------------------------------------------------------
7730 #if defined(OEM_BUILD)
7732 #define NUM_OEM_UPSELL_SCREENS 3
7733 #define OEM_UPSELL_SCREEN_DELAY 10000
7735 static int Oem_upsell_bitmaps_loaded = 0;
7736 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7737 static int Oem_upsell_screen_number = 0;
7738 static int Oem_upsell_show_next_bitmap_time;
7741 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7754 static int Oem_normal_cursor = -1;
7755 static int Oem_web_cursor = -1;
7756 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7757 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7759 void oem_upsell_next_screen()
7761 Oem_upsell_screen_number++;
7762 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7763 // extra long delay, mouse shown on last upsell
7764 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7768 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7772 void oem_upsell_load_bitmaps()
7776 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7777 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7781 void oem_upsell_unload_bitmaps()
7785 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7786 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7787 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7792 Oem_upsell_bitmaps_loaded = 0;
7795 // clickable hotspot on 3rd OEM upsell screen
7796 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7798 28, 350, 287, 96 // x, y, w, h
7801 45, 561, 460, 152 // x, y, w, h
7805 void oem_upsell_show_screens()
7807 int current_time, k;
7810 if ( !Oem_upsell_bitmaps_loaded ) {
7811 oem_upsell_load_bitmaps();
7812 Oem_upsell_bitmaps_loaded = 1;
7815 // may use upsell screens more than once
7816 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7817 Oem_upsell_screen_number = 0;
7823 int nframes; // used to pass, not really needed (should be 1)
7824 Oem_normal_cursor = gr_get_cursor_bitmap();
7825 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7826 Assert(Oem_web_cursor >= 0);
7827 if (Oem_web_cursor < 0) {
7828 Oem_web_cursor = Oem_normal_cursor;
7833 //oem_reset_trailer_timer();
7835 current_time = timer_get_milliseconds();
7840 // advance screen on keypress or timeout
7841 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7842 oem_upsell_next_screen();
7845 // check if we are done
7846 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7847 Oem_upsell_screen_number--;
7850 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7855 // show me the upsell
7856 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7857 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7861 // if this is the 3rd upsell, make it clickable, d00d
7862 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7864 int button_state = mouse_get_pos(&mx, &my);
7865 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])
7866 && (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]) )
7869 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7872 if (button_state & MOUSE_LEFT_BUTTON) {
7874 multi_pxo_url(OEM_UPSELL_URL);
7878 // switch cursor back to normal one
7879 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7884 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7894 oem_upsell_unload_bitmaps();
7896 // switch cursor back to normal one
7897 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7901 #endif // defined(OEM_BUILD)
7902 // ----------------------------------------------------------------
7904 // OEM UPSELL SCREENS END
7906 // ----------------------------------------------------------------
7910 // ----------------------------------------------------------------
7912 // DEMO UPSELL SCREENS BEGIN
7914 // ----------------------------------------------------------------
7918 //#define NUM_DEMO_UPSELL_SCREENS 4
7920 #define NUM_DEMO_UPSELL_SCREENS 2
7921 #define DEMO_UPSELL_SCREEN_DELAY 3000
7923 static int Demo_upsell_bitmaps_loaded = 0;
7924 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7925 static int Demo_upsell_screen_number = 0;
7926 static int Demo_upsell_show_next_bitmap_time;
7929 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7942 void demo_upsell_next_screen()
7944 Demo_upsell_screen_number++;
7945 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7946 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7948 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7952 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7953 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7954 #ifndef HARDWARE_ONLY
7955 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7962 void demo_upsell_load_bitmaps()
7966 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7967 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7971 void demo_upsell_unload_bitmaps()
7975 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7976 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7977 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7982 Demo_upsell_bitmaps_loaded = 0;
7985 void demo_upsell_show_screens()
7987 int current_time, k;
7990 if ( !Demo_upsell_bitmaps_loaded ) {
7991 demo_upsell_load_bitmaps();
7992 Demo_upsell_bitmaps_loaded = 1;
7995 // may use upsell screens more than once
7996 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7997 Demo_upsell_screen_number = 0;
8004 demo_reset_trailer_timer();
8006 current_time = timer_get_milliseconds();
8013 // don't time out, wait for keypress
8015 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8016 demo_upsell_next_screen();
8021 demo_upsell_next_screen();
8024 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8025 Demo_upsell_screen_number--;
8028 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8033 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8034 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8039 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8049 demo_upsell_unload_bitmaps();
8054 // ----------------------------------------------------------------
8056 // DEMO UPSELL SCREENS END
8058 // ----------------------------------------------------------------
8061 // ----------------------------------------------------------------
8063 // Subspace Ambient Sound START
8065 // ----------------------------------------------------------------
8067 static int Subspace_ambient_left_channel = -1;
8068 static int Subspace_ambient_right_channel = -1;
8071 void game_start_subspace_ambient_sound()
8073 if ( Subspace_ambient_left_channel < 0 ) {
8074 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8077 if ( Subspace_ambient_right_channel < 0 ) {
8078 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8082 void game_stop_subspace_ambient_sound()
8084 if ( Subspace_ambient_left_channel >= 0 ) {
8085 snd_stop(Subspace_ambient_left_channel);
8086 Subspace_ambient_left_channel = -1;
8089 if ( Subspace_ambient_right_channel >= 0 ) {
8090 snd_stop(Subspace_ambient_right_channel);
8091 Subspace_ambient_right_channel = -1;
8095 // ----------------------------------------------------------------
8097 // Subspace Ambient Sound END
8099 // ----------------------------------------------------------------
8101 // ----------------------------------------------------------------
8103 // CDROM detection code START
8105 // ----------------------------------------------------------------
8107 #define CD_SIZE_72_MINUTE_MAX (697000000)
8109 uint game_get_cd_used_space(char *path)
8113 char use_path[512] = "";
8114 char sub_path[512] = "";
8115 WIN32_FIND_DATA find;
8118 // recurse through all files and directories
8119 strcpy(use_path, path);
8120 strcat(use_path, "*.*");
8121 find_handle = FindFirstFile(use_path, &find);
8124 if(find_handle == INVALID_HANDLE_VALUE){
8130 // subdirectory. make sure to ignore . and ..
8131 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8133 strcpy(sub_path, path);
8134 strcat(sub_path, find.cFileName);
8135 strcat(sub_path, "\\");
8136 total += game_get_cd_used_space(sub_path);
8138 total += (uint)find.nFileSizeLow;
8140 } while(FindNextFile(find_handle, &find));
8143 FindClose(find_handle);
8155 // if volume_name is non-null, the CD name must match that
8156 int find_freespace_cd(char *volume_name)
8159 char oldpath[MAX_PATH];
8163 int volume_match = 0;
8167 GetCurrentDirectory(MAX_PATH, oldpath);
8169 for (i = 0; i < 26; i++)
8175 path[0] = (char)('A'+i);
8176 if (GetDriveType(path) == DRIVE_CDROM) {
8178 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8179 nprintf(("CD", "CD volume: %s\n", volume));
8181 // check for any CD volume
8182 int volume1_present = 0;
8183 int volume2_present = 0;
8184 int volume3_present = 0;
8186 char full_check[512] = "";
8188 // look for setup.exe
8189 strcpy(full_check, path);
8190 strcat(full_check, "setup.exe");
8191 find_handle = _findfirst(full_check, &find);
8192 if(find_handle != -1){
8193 volume1_present = 1;
8194 _findclose(find_handle);
8197 // look for intro.mve
8198 strcpy(full_check, path);
8199 strcat(full_check, "intro.mve");
8200 find_handle = _findfirst(full_check, &find);
8201 if(find_handle != -1){
8202 volume2_present = 1;
8203 _findclose(find_handle);
8206 // look for endpart1.mve
8207 strcpy(full_check, path);
8208 strcat(full_check, "endpart1.mve");
8209 find_handle = _findfirst(full_check, &find);
8210 if(find_handle != -1){
8211 volume3_present = 1;
8212 _findclose(find_handle);
8215 // see if we have the specific CD we're looking for
8216 if ( volume_name ) {
8218 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8222 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8226 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8230 if ( volume1_present || volume2_present || volume3_present ) {
8235 // 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
8236 if ( volume_match ){
8238 // 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
8239 if(volume2_present || volume3_present) {
8240 // first step - check to make sure its a cdrom
8241 if(GetDriveType(path) != DRIVE_CDROM){
8245 #if !defined(OEM_BUILD)
8246 // oem not on 80 min cds, so dont check tha size
8248 uint used_space = game_get_cd_used_space(path);
8249 if(used_space < CD_SIZE_72_MINUTE_MAX){
8252 #endif // !defined(OEM_BUILD)
8260 #endif // RELEASE_REAL
8266 SetCurrentDirectory(oldpath);
8275 int set_cdrom_path(int drive_num)
8279 if (drive_num < 0) { //no CD
8281 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8284 strcpy(Game_CDROM_dir,""); //set directory
8288 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8304 i = find_freespace_cd();
8306 rval = set_cdrom_path(i);
8310 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8312 nprintf(("CD", "FreeSpace CD not found\n"));
8320 int Last_cd_label_found = 0;
8321 char Last_cd_label[256];
8323 int game_cd_changed()
8330 if ( strlen(Game_CDROM_dir) == 0 ) {
8334 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8336 if ( found != Last_cd_label_found ) {
8337 Last_cd_label_found = found;
8339 mprintf(( "CD '%s' was inserted\n", label ));
8342 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8346 if ( Last_cd_label_found ) {
8347 if ( !stricmp( Last_cd_label, label )) {
8348 //mprintf(( "CD didn't change\n" ));
8350 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8354 // none found before, none found now.
8355 //mprintf(( "still no CD...\n" ));
8359 Last_cd_label_found = found;
8361 strcpy( Last_cd_label, label );
8363 strcpy( Last_cd_label, "" );
8374 // check if _any_ FreeSpace2 CDs are in the drive
8375 // return: 1 => CD now in drive
8376 // 0 => Could not find CD, they refuse to put it in the drive
8377 int game_do_cd_check(char *volume_name)
8379 #if !defined(GAME_CD_CHECK)
8385 int num_attempts = 0;
8386 int refresh_files = 0;
8388 int path_set_ok, popup_rval;
8390 cd_drive_num = find_freespace_cd(volume_name);
8391 path_set_ok = set_cdrom_path(cd_drive_num);
8392 if ( path_set_ok ) {
8394 if ( refresh_files ) {
8406 // no CD found, so prompt user
8407 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8409 if ( popup_rval != 1 ) {
8414 if ( num_attempts++ > 5 ) {
8425 // check if _any_ FreeSpace2 CDs are in the drive
8426 // return: 1 => CD now in drive
8427 // 0 => Could not find CD, they refuse to put it in the drive
8428 int game_do_cd_check_specific(char *volume_name, int cdnum)
8433 int num_attempts = 0;
8434 int refresh_files = 0;
8436 int path_set_ok, popup_rval;
8438 cd_drive_num = find_freespace_cd(volume_name);
8439 path_set_ok = set_cdrom_path(cd_drive_num);
8440 if ( path_set_ok ) {
8442 if ( refresh_files ) {
8453 // no CD found, so prompt user
8454 #if defined(DVD_MESSAGE_HACK)
8455 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8457 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8460 if ( popup_rval != 1 ) {
8465 if ( num_attempts++ > 5 ) {
8475 // only need to do this in RELEASE_REAL
8476 int game_do_cd_mission_check(char *filename)
8482 fs_builtin_mission *m = game_find_builtin_mission(filename);
8484 // check for changed CD
8485 if(game_cd_changed()){
8490 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8494 // not builtin, so do a general check (any FS2 CD will do)
8496 return game_do_cd_check();
8499 // does not have any CD requirement, do a general check
8500 if(strlen(m->cd_volume) <= 0){
8501 return game_do_cd_check();
8505 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8507 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8509 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8512 return game_do_cd_check();
8515 // did we find the cd?
8516 if(find_freespace_cd(m->cd_volume) >= 0){
8520 // make sure the volume exists
8521 int num_attempts = 0;
8522 int refresh_files = 0;
8524 int path_set_ok, popup_rval;
8526 cd_drive_num = find_freespace_cd(m->cd_volume);
8527 path_set_ok = set_cdrom_path(cd_drive_num);
8528 if ( path_set_ok ) {
8530 if ( refresh_files ) {
8537 // no CD found, so prompt user
8538 #if defined(DVD_MESSAGE_HACK)
8539 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8541 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8545 if ( popup_rval != 1 ) {
8550 if ( num_attempts++ > 5 ) {
8562 // ----------------------------------------------------------------
8564 // CDROM detection code END
8566 // ----------------------------------------------------------------
8568 // ----------------------------------------------------------------
8569 // SHIPS TBL VERIFICATION STUFF
8572 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8573 #define NUM_SHIPS_TBL_CHECKSUMS 1
8576 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8577 1696074201, // FS2 demo
8581 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8582 -463907578, // US - beta 1
8583 1696074201, // FS2 demo
8586 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8587 // -1022810006, // 1.0 FULL
8588 -1254285366 // 1.2 FULL (German)
8592 void verify_ships_tbl()
8596 Game_ships_tbl_valid = 1;
8602 // detect if the packfile exists
8603 CFILE *detect = cfopen("ships.tbl", "rb");
8604 Game_ships_tbl_valid = 0;
8608 Game_ships_tbl_valid = 0;
8612 // get the long checksum of the file
8614 cfseek(detect, 0, SEEK_SET);
8615 cf_chksum_long(detect, &file_checksum);
8619 // now compare the checksum/filesize against known #'s
8620 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8621 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8622 Game_ships_tbl_valid = 1;
8629 DCF(shipspew, "display the checksum for the current ships.tbl")
8632 CFILE *detect = cfopen("ships.tbl", "rb");
8633 // get the long checksum of the file
8635 cfseek(detect, 0, SEEK_SET);
8636 cf_chksum_long(detect, &file_checksum);
8639 dc_printf("%d", file_checksum);
8642 // ----------------------------------------------------------------
8643 // WEAPONS TBL VERIFICATION STUFF
8646 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8647 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8650 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8651 -266420030, // demo 1
8655 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8656 141718090, // US - beta 1
8657 -266420030, // demo 1
8660 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8661 // 399297860, // 1.0 FULL
8662 -553984927 // 1.2 FULL (german)
8666 void verify_weapons_tbl()
8670 Game_weapons_tbl_valid = 1;
8676 // detect if the packfile exists
8677 CFILE *detect = cfopen("weapons.tbl", "rb");
8678 Game_weapons_tbl_valid = 0;
8682 Game_weapons_tbl_valid = 0;
8686 // get the long checksum of the file
8688 cfseek(detect, 0, SEEK_SET);
8689 cf_chksum_long(detect, &file_checksum);
8693 // now compare the checksum/filesize against known #'s
8694 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8695 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8696 Game_weapons_tbl_valid = 1;
8703 DCF(wepspew, "display the checksum for the current weapons.tbl")
8706 CFILE *detect = cfopen("weapons.tbl", "rb");
8707 // get the long checksum of the file
8709 cfseek(detect, 0, SEEK_SET);
8710 cf_chksum_long(detect, &file_checksum);
8713 dc_printf("%d", file_checksum);
8716 // if the game is running using hacked data
8717 int game_hacked_data()
8720 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8728 void display_title_screen()
8730 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8731 ///int title_bitmap;
8734 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8735 if (title_bitmap == -1) {
8741 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8742 extern void d3d_start_frame();
8748 gr_set_bitmap(title_bitmap);
8755 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8756 extern void d3d_stop_frame();
8764 bm_unload(title_bitmap);
8765 #endif // FS2_DEMO || OEM_BUILD
8768 // return true if the game is running with "low memory", which is less than 48MB
8769 bool game_using_low_mem()
8771 if (Use_low_mem == 0) {