2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.12 2002/06/02 00:31:35 relnev
11 * implemented osregistry
13 * Revision 1.11 2002/06/01 09:00:34 relnev
14 * silly debug memmanager
16 * Revision 1.10 2002/06/01 07:12:32 relnev
17 * a few NDEBUG updates.
19 * removed a few warnings.
21 * Revision 1.9 2002/05/31 03:05:59 relnev
24 * Revision 1.8 2002/05/29 02:52:32 theoddone33
25 * Enable OpenGL renderer
27 * Revision 1.7 2002/05/28 08:52:03 relnev
28 * implemented two assembly stubs.
30 * cleaned up a few warnings.
32 * added a little demo hackery to make it progress a little farther.
34 * Revision 1.6 2002/05/28 06:28:20 theoddone33
35 * Filesystem mods, actually reads some data files now
37 * Revision 1.5 2002/05/28 04:07:28 theoddone33
38 * New graphics stubbing arrangement
40 * Revision 1.4 2002/05/27 22:46:52 theoddone33
41 * Remove more undefined symbols
43 * Revision 1.3 2002/05/26 23:31:18 relnev
44 * added a few files that needed to be compiled
46 * freespace.cpp: now compiles
48 * Revision 1.2 2002/05/07 03:16:44 theoddone33
49 * The Great Newline Fix
51 * Revision 1.1.1.1 2002/05/03 03:28:09 root
55 * 201 6/16/00 3:15p Jefff
56 * sim of the year dvd version changes, a few german soty localization
59 * 200 11/03/99 11:06a Jefff
62 * 199 10/26/99 5:07p Jamest
63 * fixed jeffs dumb debug code
65 * 198 10/25/99 5:53p Jefff
66 * call control_config_common_init() on startup
68 * 197 10/14/99 10:18a Daveb
69 * Fixed incorrect CD checking problem on standalone server.
71 * 196 10/13/99 9:22a Daveb
72 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
73 * related to movies. Fixed launcher spawning from PXO screen.
75 * 195 10/06/99 11:05a Jefff
76 * new oem upsell 3 hotspot coords
78 * 194 10/06/99 10:31a Jefff
81 * 193 10/01/99 9:10a Daveb
84 * 192 9/15/99 4:57a Dave
85 * Updated ships.tbl checksum
87 * 191 9/15/99 3:58a Dave
88 * Removed framerate warning at all times.
90 * 190 9/15/99 3:16a Dave
91 * Remove mt-011.fs2 from the builtin mission list.
93 * 189 9/15/99 1:45a Dave
94 * Don't init joystick on standalone. Fixed campaign mode on standalone.
95 * Fixed no-score-report problem in TvT
97 * 188 9/14/99 6:08a Dave
98 * Updated (final) single, multi, and campaign list.
100 * 187 9/14/99 3:26a Dave
101 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
102 * respawn-too-early problem. Made a few crash points safe.
104 * 186 9/13/99 4:52p Dave
107 * 185 9/12/99 8:09p Dave
108 * Fixed problem where skip-training button would cause mission messages
109 * not to get paged out for the current mission.
111 * 184 9/10/99 11:53a Dave
112 * Shutdown graphics before sound to eliminate apparent lockups when
113 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
115 * 183 9/09/99 11:40p Dave
116 * Handle an Assert() in beam code. Added supernova sounds. Play the right
117 * 2 end movies properly, based upon what the player did in the mission.
119 * 182 9/08/99 10:29p Dave
120 * Make beam sound pausing and unpausing much safer.
122 * 181 9/08/99 10:01p Dave
123 * Make sure game won't run in a drive's root directory. Make sure
124 * standalone routes suqad war messages properly to the host.
126 * 180 9/08/99 3:22p Dave
127 * Updated builtin mission list.
129 * 179 9/08/99 12:01p Jefff
130 * fixed Game_builtin_mission_list typo on Training-2.fs2
132 * 178 9/08/99 9:48a Andsager
133 * Add force feedback for engine wash.
135 * 177 9/07/99 4:01p Dave
136 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
137 * does everything properly (setting up address when binding). Remove
138 * black rectangle background from UI_INPUTBOX.
140 * 176 9/13/99 2:40a Dave
141 * Comment in full 80 minute CD check for RELEASE_REAL builds.
143 * 175 9/06/99 6:38p Dave
144 * Improved CD detection code.
146 * 174 9/06/99 1:30a Dave
147 * Intermediate checkin. Started on enforcing CD-in-drive to play the
150 * 173 9/06/99 1:16a Dave
151 * Make sure the user sees the intro movie.
153 * 172 9/04/99 8:00p Dave
154 * Fixed up 1024 and 32 bit movie support.
156 * 171 9/03/99 1:32a Dave
157 * CD checking by act. Added support to play 2 cutscenes in a row
158 * seamlessly. Fixed super low level cfile bug related to files in the
159 * root directory of a CD. Added cheat code to set campaign mission # in
162 * 170 9/01/99 10:49p Dave
163 * Added nice SquadWar checkbox to the client join wait screen.
165 * 169 9/01/99 10:14a Dave
168 * 168 8/29/99 4:51p Dave
169 * Fixed damaged checkin.
171 * 167 8/29/99 4:18p Andsager
172 * New "burst" limit for friendly damage. Also credit more damage done
173 * against large friendly ships.
175 * 166 8/27/99 6:38p Alanl
176 * crush the blasted repeating messages bug
178 * 164 8/26/99 9:09p Dave
179 * Force framerate check in everything but a RELEASE_REAL build.
181 * 163 8/26/99 9:45a Dave
182 * First pass at easter eggs and cheats.
184 * 162 8/24/99 8:55p Dave
185 * Make sure nondimming pixels work properly in tech menu.
187 * 161 8/24/99 1:49a Dave
188 * Fixed client-side afterburner stuttering. Added checkbox for no version
189 * checking on PXO join. Made button info passing more friendly between
192 * 160 8/22/99 5:53p Dave
193 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
194 * instead of ship designations for multiplayer players.
196 * 159 8/22/99 1:19p Dave
197 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
198 * which d3d cards are detected.
200 * 158 8/20/99 2:09p Dave
201 * PXO banner cycling.
203 * 157 8/19/99 10:59a Dave
204 * Packet loss detection.
206 * 156 8/19/99 10:12a Alanl
207 * preload mission-specific messages on machines greater than 48MB
209 * 155 8/16/99 4:04p Dave
210 * Big honking checkin.
212 * 154 8/11/99 5:54p Dave
213 * Fixed collision problem. Fixed standalone ghost problem.
215 * 153 8/10/99 7:59p Jefff
218 * 152 8/10/99 6:54p Dave
219 * Mad optimizations. Added paging to the nebula effect.
221 * 151 8/10/99 3:44p Jefff
222 * loads Intelligence information on startup
224 * 150 8/09/99 3:47p Dave
225 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
226 * non-nebula missions.
228 * 149 8/09/99 2:21p Andsager
229 * Fix patching from multiplayer direct to launcher update tab.
231 * 148 8/09/99 10:36a Dave
232 * Version info for game.
234 * 147 8/06/99 9:46p Dave
235 * Hopefully final changes for the demo.
237 * 146 8/06/99 3:34p Andsager
238 * Make title version info "(D)" -> "D" show up nicely
240 * 145 8/06/99 2:59p Adamp
241 * Fixed NT launcher/update problem.
243 * 144 8/06/99 1:52p Dave
244 * Bumped up MAX_BITMAPS for the demo.
246 * 143 8/06/99 12:17p Andsager
247 * Demo: down to just 1 demo dog
249 * 142 8/05/99 9:39p Dave
250 * Yet another new checksum.
252 * 141 8/05/99 6:19p Dave
253 * New demo checksums.
255 * 140 8/05/99 5:31p Andsager
256 * Up demo version 1.01
258 * 139 8/05/99 4:22p Andsager
259 * No time limit on upsell screens. Reverse order of display of upsell
262 * 138 8/05/99 4:17p Dave
263 * Tweaks to client interpolation.
265 * 137 8/05/99 3:52p Danw
267 * 136 8/05/99 3:01p Danw
269 * 135 8/05/99 2:43a Anoop
270 * removed duplicate definition.
272 * 134 8/05/99 2:13a Dave
275 * 133 8/05/99 2:05a Dave
278 * 132 8/05/99 1:22a Andsager
281 * 131 8/04/99 9:51p Andsager
282 * Add title screen to demo
284 * 130 8/04/99 6:47p Jefff
285 * fixed link error resulting from #ifdefs
287 * 129 8/04/99 6:26p Dave
288 * Updated ship tbl checksum.
290 * 128 8/04/99 5:40p Andsager
291 * Add multiple demo dogs
293 * 127 8/04/99 5:36p Andsager
294 * Show upsell screens at end of demo campaign before returning to main
297 * 126 8/04/99 11:42a Danw
298 * tone down EAX reverb
300 * 125 8/04/99 11:23a Dave
301 * Updated demo checksums.
303 * 124 8/03/99 11:02p Dave
304 * Maybe fixed sync problems in multiplayer.
306 * 123 8/03/99 6:21p Jefff
309 * 122 8/03/99 3:44p Andsager
310 * Launch laucher if trying to run FS without first having configured
313 * 121 8/03/99 12:45p Dave
316 * 120 8/02/99 9:13p Dave
319 * 119 7/30/99 10:31p Dave
320 * Added comm menu to the configurable hud files.
322 * 118 7/30/99 5:17p Andsager
323 * first fs2demo checksums
325 * 117 7/29/99 3:09p Anoop
327 * 116 7/29/99 12:05a Dave
328 * Nebula speed optimizations.
330 * 115 7/27/99 8:59a Andsager
331 * Make major, minor version consistent for all builds. Only show major
332 * and minor for launcher update window.
334 * 114 7/26/99 5:50p Dave
335 * Revised ingame join. Better? We'll see....
337 * 113 7/26/99 5:27p Andsager
338 * Add training mission as builtin to demo build
340 * 112 7/24/99 1:54p Dave
341 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
344 * 111 7/22/99 4:00p Dave
345 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
347 * 110 7/21/99 8:10p Dave
348 * First run of supernova effect.
350 * 109 7/20/99 1:49p Dave
351 * Peter Drake build. Fixed some release build warnings.
353 * 108 7/19/99 2:26p Andsager
354 * set demo multiplayer missions
356 * 107 7/18/99 5:19p Dave
357 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
359 * 106 7/16/99 1:50p Dave
360 * 8 bit aabitmaps. yay.
362 * 105 7/15/99 3:07p Dave
363 * 32 bit detection support. Mouse coord commandline.
365 * 104 7/15/99 2:13p Dave
366 * Added 32 bit detection.
368 * 103 7/15/99 9:20a Andsager
369 * FS2_DEMO initial checkin
371 * 102 7/14/99 11:02a Dave
372 * Skill level default back to easy. Blech.
374 * 101 7/09/99 5:54p Dave
375 * Seperated cruiser types into individual types. Added tons of new
376 * briefing icons. Campaign screen.
378 * 100 7/08/99 4:43p Andsager
379 * New check for sparky_hi and print if not found.
381 * 99 7/08/99 10:53a Dave
382 * New multiplayer interpolation scheme. Not 100% done yet, but still
383 * better than the old way.
385 * 98 7/06/99 4:24p Dave
386 * Mid-level checkin. Starting on some potentially cool multiplayer
389 * 97 7/06/99 3:35p Andsager
390 * Allow movie to play before red alert mission.
392 * 96 7/03/99 5:50p Dave
393 * Make rotated bitmaps draw properly in padlock views.
395 * 95 7/02/99 9:55p Dave
396 * Player engine wash sound.
398 * 94 7/02/99 4:30p Dave
399 * Much more sophisticated lightning support.
401 * 93 6/29/99 7:52p Dave
402 * Put in exception handling in FS2.
404 * 92 6/22/99 9:37p Dave
405 * Put in pof spewing.
407 * 91 6/16/99 4:06p Dave
408 * New pilot info popup. Added new draw-bitmap-as-poly function.
410 * 90 6/15/99 1:56p Andsager
411 * For release builds, allow start up in high res only with
414 * 89 6/15/99 9:34a Dave
415 * Fixed key checking in single threaded version of the stamp notification
418 * 88 6/09/99 2:55p Andsager
419 * Allow multiple asteroid subtypes (of large, medium, small) and follow
422 * 87 6/08/99 1:14a Dave
423 * Multi colored hud test.
425 * 86 6/04/99 9:52a Dave
426 * Fixed some rendering problems.
428 * 85 6/03/99 10:15p Dave
429 * Put in temporary main hall screen.
431 * 84 6/02/99 6:18p Dave
432 * Fixed TNT lockup problems! Wheeeee!
434 * 83 6/01/99 3:52p Dave
435 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
436 * dead popup, pxo find player popup, pxo private room popup.
438 * 82 5/26/99 1:28p Jasenw
439 * changed coords for loading ani
441 * 81 5/26/99 11:46a Dave
442 * Added ship-blasting lighting and made the randomization of lighting
443 * much more customizable.
445 * 80 5/24/99 5:45p Dave
446 * Added detail levels to the nebula, with a decent speedup. Split nebula
447 * lightning into its own section.
465 #include "systemvars.h"
470 #include "starfield.h"
471 #include "lighting.h"
476 #include "fireballs.h"
480 #include "floating.h"
481 #include "gamesequence.h"
483 #include "optionsmenu.h"
484 #include "playermenu.h"
485 #include "trainingmenu.h"
486 #include "techmenu.h"
489 #include "hudmessage.h"
491 #include "missiongoals.h"
492 #include "missionparse.h"
497 #include "multiutil.h"
498 #include "multimsgs.h"
502 #include "freespace.h"
503 #include "managepilot.h"
505 #include "contexthelp.h"
508 #include "missionbrief.h"
509 #include "missiondebrief.h"
511 #include "missionshipchoice.h"
513 #include "hudconfig.h"
514 #include "controlsconfig.h"
515 #include "missionmessage.h"
516 #include "missiontraining.h"
518 #include "hudtarget.h"
522 #include "eventmusic.h"
523 #include "animplay.h"
524 #include "missionweaponchoice.h"
525 #include "missionlog.h"
526 #include "audiostr.h"
528 #include "missioncampaign.h"
530 #include "missionhotkey.h"
531 #include "objectsnd.h"
532 #include "cmeasure.h"
534 #include "linklist.h"
535 #include "shockwave.h"
536 #include "afterburner.h"
541 #include "stand_gui.h"
542 #include "pcxutils.h"
543 #include "hudtargetbox.h"
544 #include "multi_xfer.h"
545 #include "hudescort.h"
546 #include "multiutil.h"
549 #include "multiteamselect.h"
552 #include "readyroom.h"
553 #include "mainhallmenu.h"
554 #include "multilag.h"
556 #include "particle.h"
558 #include "multi_ingame.h"
559 #include "snazzyui.h"
560 #include "asteroid.h"
561 #include "popupdead.h"
562 #include "multi_voice.h"
563 #include "missioncmdbrief.h"
564 #include "redalert.h"
565 #include "gameplayhelp.h"
566 #include "multilag.h"
567 #include "staticrand.h"
568 #include "multi_pmsg.h"
569 #include "levelpaging.h"
570 #include "observer.h"
571 #include "multi_pause.h"
572 #include "multi_endgame.h"
573 #include "cutscenes.h"
574 #include "multi_respawn.h"
575 // #include "movie.h"
576 #include "multi_obj.h"
577 #include "multi_log.h"
579 #include "localize.h"
580 #include "osregistry.h"
581 #include "barracks.h"
582 #include "missionpause.h"
584 #include "alphacolors.h"
585 #include "objcollide.h"
588 #include "neblightning.h"
589 #include "shipcontrails.h"
592 #include "multi_dogfight.h"
593 #include "multi_rate.h"
594 #include "muzzleflash.h"
598 #include "mainhalltemp.h"
599 #include "exceptionhandler.h"
603 #include "supernova.h"
604 #include "hudshield.h"
605 // #include "names.h"
607 #include "missionloopbrief.h"
611 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
617 // 1.00.04 5/26/98 MWA -- going final (12 pm)
618 // 1.00.03 5/26/98 MWA -- going final (3 am)
619 // 1.00.02 5/25/98 MWA -- going final
620 // 1.00.01 5/25/98 MWA -- going final
621 // 0.90 5/21/98 MWA -- getting ready for final.
622 // 0.10 4/9/98. Set by MK.
624 // Demo version: (obsolete since DEMO codebase split from tree)
625 // 0.03 4/10/98 AL. Interplay rev
626 // 0.02 4/8/98 MK. Increased when this system was modified.
627 // 0.01 4/7/98? AL. First release to Interplay QA.
630 // 1.00 5/28/98 AL. First release to Interplay QA.
632 void game_level_init(int seed = -1);
633 void game_post_level_init();
634 void game_do_frame();
635 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
636 void game_reset_time();
637 void game_show_framerate(); // draws framerate in lower right corner
639 int Game_no_clear = 0;
641 int Pofview_running = 0;
642 int Nebedit_running = 0;
644 typedef struct big_expl_flash {
645 float max_flash_intensity; // max intensity
646 float cur_flash_intensity; // cur intensity
647 int flash_start; // start time
650 #define FRAME_FILTER 16
652 #define DEFAULT_SKILL_LEVEL 1
653 int Game_skill_level = DEFAULT_SKILL_LEVEL;
655 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
656 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
658 #define EXE_FNAME ("fs2.exe")
659 #define LAUNCHER_FNAME ("freespace2.exe")
661 // JAS: Code for warphole camera.
662 // Needs to be cleaned up.
663 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
664 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
665 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
666 matrix Camera_orient = IDENTITY_MATRIX;
667 float Camera_damping = 1.0f;
668 float Camera_time = 0.0f;
669 float Warpout_time = 0.0f;
670 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
671 int Warpout_sound = -1;
673 int Use_joy_mouse = 0;
674 int Use_palette_flash = 1;
676 int Use_fullscreen_at_startup = 0;
678 int Show_area_effect = 0;
679 object *Last_view_target = NULL;
681 int dogfight_blown = 0;
684 float frametimes[FRAME_FILTER];
685 float frametotal = 0.0f;
689 int Show_framerate = 0;
691 int Show_framerate = 1;
694 int Framerate_cap = 120;
697 int Show_target_debug_info = 0;
698 int Show_target_weapons = 0;
700 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
702 int Debug_octant = -1;
704 fix Game_time_compression = F1_0;
706 // if the ships.tbl the player has is valid
707 int Game_ships_tbl_valid = 0;
709 // if the weapons.tbl the player has is valid
710 int Game_weapons_tbl_valid = 0;
714 extern int Player_attacking_enabled;
718 int Pre_player_entry;
720 int Fred_running = 0;
721 char Game_current_mission_filename[MAX_FILENAME_LEN];
722 int game_single_step = 0;
723 int last_single_step=0;
725 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
726 extern int MSG_WINDOW_Y_START;
727 extern int MSG_WINDOW_HEIGHT;
729 int game_zbuffer = 1;
730 //static int Game_music_paused;
731 static int Game_paused;
735 #define EXPIRE_BAD_CHECKSUM 1
736 #define EXPIRE_BAD_TIME 2
738 extern void ssm_init();
739 extern void ssm_level_init();
740 extern void ssm_process();
742 // static variable to contain the time this version was built
743 // commented out for now until
744 // I figure out how to get the username into the file
745 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
747 // defines and variables used for dumping frame for making trailers.
749 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
750 int Debug_dump_trigger = 0;
751 int Debug_dump_frame_count;
752 int Debug_dump_frame_num = 0;
753 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
756 // amount of time to wait after the player has died before we display the death died popup
757 #define PLAYER_DIED_POPUP_WAIT 2500
758 int Player_died_popup_wait = -1;
759 int Player_multi_died_check = -1;
761 // builtin mission list stuff
763 int Game_builtin_mission_count = 6;
764 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
765 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
766 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
767 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
768 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
769 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
770 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
772 #elif defined(PD_BUILD)
773 int Game_builtin_mission_count = 4;
774 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
775 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
776 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
777 { "sm1-01", (FSB_FROM_VOLITION), "" },
778 { "sm1-05", (FSB_FROM_VOLITION), "" },
780 #elif defined(MULTIPLAYER_BETA)
781 int Game_builtin_mission_count = 17;
782 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
784 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
785 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
786 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
787 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
788 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
789 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
790 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
791 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
792 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
793 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
794 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
795 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
796 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
797 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
798 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
799 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
800 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
802 #elif defined(OEM_BUILD)
803 int Game_builtin_mission_count = 17;
804 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
805 // oem version - act 1 only
806 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
809 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
810 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
811 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
812 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
813 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
814 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
815 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
816 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
817 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
818 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
819 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
820 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
821 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
822 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
823 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
824 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
827 int Game_builtin_mission_count = 92;
828 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
829 // single player campaign
830 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
833 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
835 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
836 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
838 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
839 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
841 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
842 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
843 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
844 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
845 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
846 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
847 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
848 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
849 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
850 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
851 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
854 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
858 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
859 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
861 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
866 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
867 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
868 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
869 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
870 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
871 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
872 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
873 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
874 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
875 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
876 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
877 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
879 // multiplayer missions
882 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
919 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
920 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
923 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
926 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
927 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
936 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
937 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
938 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
939 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
944 // Internal function prototypes
945 void game_maybe_draw_mouse(float frametime);
946 void init_animating_pointer();
947 void load_animating_pointer(char *filename, int dx, int dy);
948 void unload_animating_pointer();
949 void game_do_training_checks();
950 void game_shutdown(void);
951 void game_show_event_debug(float frametime);
952 void game_event_debug_init();
954 void demo_upsell_show_screens();
955 void game_start_subspace_ambient_sound();
956 void game_stop_subspace_ambient_sound();
957 void verify_ships_tbl();
958 void verify_weapons_tbl();
959 void display_title_screen();
961 // loading background filenames
962 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
963 "LoadingBG", // GR_640
964 "2_LoadingBG" // GR_1024
968 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
969 "Loading.ani", // GR_640
970 "2_Loading.ani" // GR_1024
973 #if defined(FS2_DEMO)
974 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
978 #elif defined(OEM_BUILD)
979 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
986 char Game_CDROM_dir[MAX_PATH_LEN];
989 // How much RAM is on this machine. Set in WinMain
990 uint Freespace_total_ram = 0;
993 float Game_flash_red = 0.0f;
994 float Game_flash_green = 0.0f;
995 float Game_flash_blue = 0.0f;
996 float Sun_spot = 0.0f;
997 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
999 // game shudder stuff (in ms)
1000 int Game_shudder_time = -1;
1001 int Game_shudder_total = 0;
1002 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1005 sound_env Game_sound_env;
1006 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1007 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1009 int Game_sound_env_update_timestamp;
1011 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1014 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1016 fs_builtin_mission *game_find_builtin_mission(char *filename)
1020 // look through all existing builtin missions
1021 for(idx=0; idx<Game_builtin_mission_count; idx++){
1022 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1023 return &Game_builtin_mission_list[idx];
1031 int game_get_default_skill_level()
1033 return DEFAULT_SKILL_LEVEL;
1037 void game_flash_reset()
1039 Game_flash_red = 0.0f;
1040 Game_flash_green = 0.0f;
1041 Game_flash_blue = 0.0f;
1043 Big_expl_flash.max_flash_intensity = 0.0f;
1044 Big_expl_flash.cur_flash_intensity = 0.0f;
1045 Big_expl_flash.flash_start = 0;
1048 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1049 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1051 void game_framerate_check_init()
1053 // zero critical time
1054 Gf_critical_time = 0.0f;
1057 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1058 // if this is a glide card
1059 if(gr_screen.mode == GR_GLIDE){
1061 extern GrHwConfiguration hwconfig;
1064 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1065 Gf_critical = 15.0f;
1069 Gf_critical = 10.0f;
1074 Gf_critical = 15.0f;
1077 // d3d. only care about good cards here I guess (TNT)
1079 Gf_critical = 15.0f;
1082 // if this is a glide card
1083 if(gr_screen.mode == GR_GLIDE){
1085 extern GrHwConfiguration hwconfig;
1088 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1089 Gf_critical = 25.0f;
1093 Gf_critical = 20.0f;
1098 Gf_critical = 25.0f;
1101 // d3d. only care about good cards here I guess (TNT)
1103 Gf_critical = 25.0f;
1108 extern float Framerate;
1109 void game_framerate_check()
1113 // if the current framerate is above the critical level, add frametime
1114 if(Framerate >= Gf_critical){
1115 Gf_critical_time += flFrametime;
1118 if(!Show_framerate){
1122 // display if we're above the critical framerate
1123 if(Framerate < Gf_critical){
1124 gr_set_color_fast(&Color_bright_red);
1125 gr_string(200, y_start, "Framerate warning");
1130 // display our current pct of good frametime
1131 if(f2fl(Missiontime) >= 0.0f){
1132 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1135 gr_set_color_fast(&Color_bright_green);
1137 gr_set_color_fast(&Color_bright_red);
1140 gr_printf(200, y_start, "%d%%", (int)pct);
1147 // Adds a flash effect. These can be positive or negative.
1148 // The range will get capped at around -1 to 1, so stick
1149 // with a range like that.
1150 void game_flash( float r, float g, float b )
1152 Game_flash_red += r;
1153 Game_flash_green += g;
1154 Game_flash_blue += b;
1156 if ( Game_flash_red < -1.0f ) {
1157 Game_flash_red = -1.0f;
1158 } else if ( Game_flash_red > 1.0f ) {
1159 Game_flash_red = 1.0f;
1162 if ( Game_flash_green < -1.0f ) {
1163 Game_flash_green = -1.0f;
1164 } else if ( Game_flash_green > 1.0f ) {
1165 Game_flash_green = 1.0f;
1168 if ( Game_flash_blue < -1.0f ) {
1169 Game_flash_blue = -1.0f;
1170 } else if ( Game_flash_blue > 1.0f ) {
1171 Game_flash_blue = 1.0f;
1176 // Adds a flash for Big Ship explosions
1177 // cap range from 0 to 1
1178 void big_explosion_flash(float flash)
1180 Big_expl_flash.flash_start = timestamp(1);
1184 } else if (flash < 0.0f) {
1188 Big_expl_flash.max_flash_intensity = flash;
1189 Big_expl_flash.cur_flash_intensity = 0.0f;
1192 // Amount to diminish palette towards normal, per second.
1193 #define DIMINISH_RATE 0.75f
1194 #define SUN_DIMINISH_RATE 6.00f
1198 float sn_glare_scale = 1.7f;
1201 dc_get_arg(ARG_FLOAT);
1202 sn_glare_scale = Dc_arg_float;
1205 float Supernova_last_glare = 0.0f;
1206 void game_sunspot_process(float frametime)
1210 float Sun_spot_goal = 0.0f;
1213 sn_stage = supernova_active();
1215 // sunspot differently based on supernova stage
1217 // approaching. player still in control
1220 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1223 light_get_global_dir(&light_dir, 0);
1225 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1228 // scale it some more
1229 dot = dot * (0.5f + (pct * 0.5f));
1232 Sun_spot_goal += (dot * sn_glare_scale);
1235 // draw the sun glow
1236 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1237 // draw the glow for this sun
1238 stars_draw_sun_glow(0);
1241 Supernova_last_glare = Sun_spot_goal;
1244 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1247 Sun_spot_goal = 0.9f;
1248 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1250 if(Sun_spot_goal > 1.0f){
1251 Sun_spot_goal = 1.0f;
1254 Sun_spot_goal *= sn_glare_scale;
1255 Supernova_last_glare = Sun_spot_goal;
1258 // fade to white. display dead popup
1261 Supernova_last_glare += (2.0f * flFrametime);
1262 if(Supernova_last_glare > 2.0f){
1263 Supernova_last_glare = 2.0f;
1266 Sun_spot_goal = Supernova_last_glare;
1273 // check sunspots for all suns
1274 n_lights = light_get_global_count();
1277 for(idx=0; idx<n_lights; idx++){
1278 //(vector *eye_pos, matrix *eye_orient)
1279 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1282 light_get_global_dir(&light_dir, idx);
1284 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1286 Sun_spot_goal += (float)pow(dot,85.0f);
1288 // draw the glow for this sun
1289 stars_draw_sun_glow(idx);
1291 Sun_spot_goal = 0.0f;
1297 Sun_spot_goal = 0.0f;
1301 float dec_amount = frametime*SUN_DIMINISH_RATE;
1303 if ( Sun_spot < Sun_spot_goal ) {
1304 Sun_spot += dec_amount;
1305 if ( Sun_spot > Sun_spot_goal ) {
1306 Sun_spot = Sun_spot_goal;
1308 } else if ( Sun_spot > Sun_spot_goal ) {
1309 Sun_spot -= dec_amount;
1310 if ( Sun_spot < Sun_spot_goal ) {
1311 Sun_spot = Sun_spot_goal;
1317 // Call once a frame to diminish the
1318 // flash effect to 0.
1319 void game_flash_diminish(float frametime)
1321 float dec_amount = frametime*DIMINISH_RATE;
1323 if ( Game_flash_red > 0.0f ) {
1324 Game_flash_red -= dec_amount;
1325 if ( Game_flash_red < 0.0f )
1326 Game_flash_red = 0.0f;
1328 Game_flash_red += dec_amount;
1329 if ( Game_flash_red > 0.0f )
1330 Game_flash_red = 0.0f;
1333 if ( Game_flash_green > 0.0f ) {
1334 Game_flash_green -= dec_amount;
1335 if ( Game_flash_green < 0.0f )
1336 Game_flash_green = 0.0f;
1338 Game_flash_green += dec_amount;
1339 if ( Game_flash_green > 0.0f )
1340 Game_flash_green = 0.0f;
1343 if ( Game_flash_blue > 0.0f ) {
1344 Game_flash_blue -= dec_amount;
1345 if ( Game_flash_blue < 0.0f )
1346 Game_flash_blue = 0.0f;
1348 Game_flash_blue += dec_amount;
1349 if ( Game_flash_blue > 0.0f )
1350 Game_flash_blue = 0.0f;
1353 // update big_explosion_cur_flash
1354 #define TIME_UP 1500
1355 #define TIME_DOWN 2500
1356 int duration = TIME_UP + TIME_DOWN;
1357 int time = timestamp_until(Big_expl_flash.flash_start);
1358 if (time > -duration) {
1360 if (time < TIME_UP) {
1361 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1364 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1368 if ( Use_palette_flash ) {
1370 // static int or=0, og=0, ob=0;
1372 // Change the 200 to change the color range of colors.
1373 r = fl2i( Game_flash_red*128.0f );
1374 g = fl2i( Game_flash_green*128.0f );
1375 b = fl2i( Game_flash_blue*128.0f );
1377 if ( Sun_spot > 0.0f ) {
1378 r += fl2i(Sun_spot*128.0f);
1379 g += fl2i(Sun_spot*128.0f);
1380 b += fl2i(Sun_spot*128.0f);
1383 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1384 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1385 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1386 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1389 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1390 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1391 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1393 if ( (r!=0) || (g!=0) || (b!=0) ) {
1394 gr_flash( r, g, b );
1396 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1407 void game_level_close()
1409 // De-Initialize the game subsystems
1410 message_mission_shutdown();
1411 event_music_level_close();
1412 game_stop_looped_sounds();
1414 obj_snd_level_close(); // uninit object-linked persistant sounds
1415 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1416 anim_level_close(); // stop and clean up any anim instances
1417 shockwave_level_close();
1418 fireball_level_close();
1420 mission_event_shutdown();
1421 asteroid_level_close();
1422 model_cache_reset(); // Reset/free all the model caching stuff
1423 flak_level_close(); // unload flak stuff
1424 neb2_level_close(); // shutdown gaseous nebula stuff
1427 mflash_level_close();
1429 audiostream_unpause_all();
1434 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1435 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1436 void game_level_init(int seed)
1438 // seed the random number generator
1440 // if no seed was passed, seed the generator either from the time value, or from the
1441 // netgame security flags -- ensures that all players in multiplayer game will have the
1442 // same randon number sequence (with static rand functions)
1443 if ( Game_mode & GM_NORMAL ) {
1444 Game_level_seed = time(NULL);
1446 Game_level_seed = Netgame.security;
1449 // mwa 9/17/98 -- maybe this assert isn't needed????
1450 Assert( !(Game_mode & GM_MULTIPLAYER) );
1451 Game_level_seed = seed;
1453 srand( Game_level_seed );
1455 // semirand function needs to get re-initted every time in multiplayer
1456 if ( Game_mode & GM_MULTIPLAYER ){
1462 Key_normal_game = (Game_mode & GM_NORMAL);
1465 Game_shudder_time = -1;
1467 // Initialize the game subsystems
1468 // timestamp_reset(); // Must be inited before everything else
1470 game_reset_time(); // resets time, and resets saved time too
1472 obj_init(); // Must be inited before the other systems
1473 model_free_all(); // Free all existing models
1474 mission_brief_common_init(); // Free all existing briefing/debriefing text
1475 weapon_level_init();
1476 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1478 player_level_init();
1479 shipfx_flash_init(); // Init the ship gun flash system.
1480 game_flash_reset(); // Reset the flash effect
1481 particle_init(); // Reset the particle system
1485 shield_hit_init(); // Initialize system for showing shield hits
1486 radar_mission_init();
1487 mission_init_goals();
1490 obj_snd_level_init(); // init object-linked persistant sounds
1492 shockwave_level_init();
1493 afterburner_level_init();
1494 scoring_level_init( &Player->stats );
1496 asteroid_level_init();
1497 control_config_clear_used_status();
1498 collide_ship_ship_sounds_init();
1500 Pre_player_entry = 1; // Means the player has not yet entered.
1501 Entry_delay_time = 0; // Could get overwritten in mission read.
1502 fireball_preload(); // page in warphole bitmaps
1504 flak_level_init(); // initialize flak - bitmaps, etc
1505 ct_level_init(); // initialize ships contrails, etc
1506 awacs_level_init(); // initialize AWACS
1507 beam_level_init(); // initialize beam weapons
1508 mflash_level_init();
1510 supernova_level_init();
1512 // multiplayer dogfight hack
1515 shipfx_engine_wash_level_init();
1519 Last_view_target = NULL;
1524 // campaign wasn't ended
1525 Campaign_ended_in_mission = 0;
1528 // called when a mission is over -- does server specific stuff.
1529 void freespace_stop_mission()
1532 Game_mode &= ~GM_IN_MISSION;
1535 // called at frame interval to process networking stuff
1536 void game_do_networking()
1538 Assert( Net_player != NULL );
1539 if (!(Game_mode & GM_MULTIPLAYER)){
1543 // see if this player should be reading/writing data. Bit is set when at join
1544 // screen onward until quits back to main menu.
1545 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1549 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1552 multi_pause_do_frame();
1557 // Loads the best palette for this level, based
1558 // on nebula color and hud color. You could just call palette_load_table with
1559 // the appropriate filename, but who wants to do that.
1560 void game_load_palette()
1562 char palette_filename[1024];
1564 // We only use 3 hud colors right now
1565 // Assert( HUD_config.color >= 0 );
1566 // Assert( HUD_config.color <= 2 );
1568 Assert( Mission_palette >= 0 );
1569 Assert( Mission_palette <= 98 );
1571 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1572 strcpy( palette_filename, NOX("gamepalette-subspace") );
1574 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1577 mprintf(( "Loading palette %s\n", palette_filename ));
1579 // palette_load_table(palette_filename);
1582 void game_post_level_init()
1584 // Stuff which gets called after mission is loaded. Because player isn't created until
1585 // after mission loads, some things must get initted after the level loads
1587 model_level_post_init();
1590 hud_setup_escort_list();
1591 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1597 game_event_debug_init();
1600 training_mission_init();
1601 asteroid_create_all();
1603 game_framerate_check_init();
1607 // An estimate as to how high the count passed to game_loading_callback will go.
1608 // This is just a guess, it seems to always be about the same. The count is
1609 // proportional to the code being executed, not the time, so this works good
1610 // for a bar, assuming the code does about the same thing each time you
1611 // load a level. You can find this value by looking at the return value
1612 // of game_busy_callback(NULL), which I conveniently print out to the
1613 // debug output window with the '=== ENDING LOAD ==' stuff.
1614 //#define COUNT_ESTIMATE 3706
1615 #define COUNT_ESTIMATE 1111
1617 int Game_loading_callback_inited = 0;
1619 int Game_loading_background = -1;
1620 anim * Game_loading_ani = NULL;
1621 anim_instance *Game_loading_ani_instance;
1622 int Game_loading_frame=-1;
1624 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1633 // This gets called 10x per second and count is the number of times
1634 // game_busy() has been called since the current callback function
1636 void game_loading_callback(int count)
1638 game_do_networking();
1640 Assert( Game_loading_callback_inited==1 );
1641 Assert( Game_loading_ani != NULL );
1643 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1644 if ( framenum > Game_loading_ani->total_frames-1 ) {
1645 framenum = Game_loading_ani->total_frames-1;
1646 } else if ( framenum < 0 ) {
1651 while ( Game_loading_frame < framenum ) {
1652 Game_loading_frame++;
1653 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1657 if ( cbitmap > -1 ) {
1658 if ( Game_loading_background > -1 ) {
1659 gr_set_bitmap( Game_loading_background );
1663 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1664 gr_set_bitmap( cbitmap );
1665 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1667 bm_release(cbitmap);
1673 void game_loading_callback_init()
1675 Assert( Game_loading_callback_inited==0 );
1677 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1678 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1681 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1682 Assert( Game_loading_ani != NULL );
1683 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1684 Assert( Game_loading_ani_instance != NULL );
1685 Game_loading_frame = -1;
1687 Game_loading_callback_inited = 1;
1689 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1694 void game_loading_callback_close()
1696 Assert( Game_loading_callback_inited==1 );
1698 // Make sure bar shows all the way over.
1699 game_loading_callback(COUNT_ESTIMATE);
1701 int real_count = game_busy_callback( NULL );
1704 Game_loading_callback_inited = 0;
1707 mprintf(( "=================== ENDING LOAD ================\n" ));
1708 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1709 mprintf(( "================================================\n" ));
1711 // to remove warnings in release build
1715 free_anim_instance(Game_loading_ani_instance);
1716 Game_loading_ani_instance = NULL;
1717 anim_free(Game_loading_ani);
1718 Game_loading_ani = NULL;
1720 bm_release( Game_loading_background );
1721 common_free_interface_palette(); // restore game palette
1722 Game_loading_background = -1;
1724 gr_set_font( FONT1 );
1727 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1729 void game_maybe_update_sound_environment()
1731 // do nothing for now
1734 // Assign the sound environment for the game, based on the current mission
1736 void game_assign_sound_environment()
1739 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1740 Game_sound_env.id = SND_ENV_DRUGGED;
1741 Game_sound_env.volume = 0.800f;
1742 Game_sound_env.damping = 1.188f;
1743 Game_sound_env.decay = 6.392f;
1745 } else if (Num_asteroids > 30) {
1746 Game_sound_env.id = SND_ENV_AUDITORIUM;
1747 Game_sound_env.volume = 0.603f;
1748 Game_sound_env.damping = 0.5f;
1749 Game_sound_env.decay = 4.279f;
1752 Game_sound_env = Game_default_sound_env;
1756 Game_sound_env = Game_default_sound_env;
1757 Game_sound_env_update_timestamp = timestamp(1);
1760 // function which gets called before actually entering the mission. It is broken down into a funciton
1761 // since it will get called in one place from a single player game and from another place for
1762 // a multiplayer game
1763 void freespace_mission_load_stuff()
1765 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1766 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1767 if(!(Game_mode & GM_STANDALONE_SERVER)){
1769 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1771 game_loading_callback_init();
1773 event_music_level_init(); // preloads the first 2 seconds for each event music track
1776 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1779 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1782 ship_assign_sound_all(); // assign engine sounds to ships
1783 game_assign_sound_environment(); // assign the sound environment for this mission
1786 // call function in missionparse.cpp to fixup player/ai stuff.
1787 mission_parse_fixup_players();
1790 // Load in all the bitmaps for this level
1795 game_loading_callback_close();
1797 // the only thing we need to call on the standalone for now.
1799 // call function in missionparse.cpp to fixup player/ai stuff.
1800 mission_parse_fixup_players();
1802 // Load in all the bitmaps for this level
1808 uint load_mission_load;
1809 uint load_post_level_init;
1810 uint load_mission_stuff;
1812 // tells the server to load the mission and initialize structures
1813 int game_start_mission()
1815 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1817 load_gl_init = time(NULL);
1819 load_gl_init = time(NULL) - load_gl_init;
1821 if (Game_mode & GM_MULTIPLAYER) {
1822 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1824 // clear multiplayer stats
1825 init_multiplayer_stats();
1828 load_mission_load = time(NULL);
1829 if (mission_load()) {
1830 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1831 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1832 gameseq_post_event(GS_EVENT_MAIN_MENU);
1834 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1839 load_mission_load = time(NULL) - load_mission_load;
1841 // If this is a red alert mission in campaign mode, bash wingman status
1842 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1843 red_alert_bash_wingman_status();
1846 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1847 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1848 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1849 // game_load_palette();
1852 load_post_level_init = time(NULL);
1853 game_post_level_init();
1854 load_post_level_init = time(NULL) - load_post_level_init;
1858 void Do_model_timings_test();
1859 Do_model_timings_test();
1863 load_mission_stuff = time(NULL);
1864 freespace_mission_load_stuff();
1865 load_mission_stuff = time(NULL) - load_mission_stuff;
1870 int Interface_framerate = 0;
1873 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1874 DCF_BOOL( show_framerate, Show_framerate )
1875 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1876 DCF_BOOL( show_target_weapons, Show_target_weapons )
1877 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1878 DCF_BOOL( sound, Sound_enabled )
1879 DCF_BOOL( zbuffer, game_zbuffer )
1880 DCF_BOOL( shield_system, New_shield_system )
1881 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1882 DCF_BOOL( player_attacking, Player_attacking_enabled )
1883 DCF_BOOL( show_waypoints, Show_waypoints )
1884 DCF_BOOL( show_area_effect, Show_area_effect )
1885 DCF_BOOL( show_net_stats, Show_net_stats )
1886 DCF_BOOL( log, Log_debug_output_to_file )
1887 DCF_BOOL( training_msg_method, Training_msg_method )
1888 DCF_BOOL( show_player_pos, Show_player_pos )
1889 DCF_BOOL(i_framerate, Interface_framerate )
1891 DCF(show_mem,"Toggles showing mem usage")
1894 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1895 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1896 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1897 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1903 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1905 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1906 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1910 DCF(show_cpu,"Toggles showing cpu usage")
1913 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1914 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1915 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1916 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1922 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1924 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1925 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1932 // AL 4-8-98: always allow players to display their framerate
1935 DCF_BOOL( show_framerate, Show_framerate )
1942 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1945 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1946 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1947 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1948 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1950 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" );
1951 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1953 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1956 DCF(palette_flash,"Toggles palette flash effect on/off")
1959 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1960 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1961 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1962 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1964 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1965 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1968 int Use_low_mem = 0;
1970 DCF(low_mem,"Uses low memory settings regardless of RAM")
1973 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1974 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1975 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1976 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1978 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1979 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1981 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1987 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1990 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1991 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1992 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1993 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1995 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1996 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1997 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2001 int Framerate_delay = 0;
2003 float Freespace_gamma = 1.0f;
2005 DCF(gamma,"Sets Gamma factor")
2008 dc_get_arg(ARG_FLOAT|ARG_NONE);
2009 if ( Dc_arg_type & ARG_FLOAT ) {
2010 Freespace_gamma = Dc_arg_float;
2012 dc_printf( "Gamma reset to 1.0f\n" );
2013 Freespace_gamma = 1.0f;
2015 if ( Freespace_gamma < 0.1f ) {
2016 Freespace_gamma = 0.1f;
2017 } else if ( Freespace_gamma > 5.0f ) {
2018 Freespace_gamma = 5.0f;
2020 gr_set_gamma(Freespace_gamma);
2022 char tmp_gamma_string[32];
2023 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2024 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2028 dc_printf( "Usage: gamma <float>\n" );
2029 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2030 Dc_status = 0; // don't print status if help is printed. Too messy.
2034 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2043 Game_current_mission_filename[0] = 0;
2045 // seed the random number generator
2046 Game_init_seed = time(NULL);
2047 srand( Game_init_seed );
2049 Framerate_delay = 0;
2055 extern void bm_init();
2061 // Initialize the timer before the os
2069 GetCurrentDirectory(1024, whee);
2072 getcwd (whee, 1024);
2075 strcat(whee, EXE_FNAME);
2077 //Initialize the libraries
2078 s1 = timer_get_milliseconds();
2079 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2082 e1 = timer_get_milliseconds();
2084 // time a bunch of cfopens
2086 s2 = timer_get_milliseconds();
2088 for(int idx=0; idx<10000; idx++){
2089 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2094 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2096 e2 = timer_get_milliseconds();
2099 if (Is_standalone) {
2100 std_init_standalone();
2102 os_init( Osreg_class_name, Osreg_app_name );
2103 os_set_title(Osreg_title);
2106 // initialize localization module. Make sure this is down AFTER initialzing OS.
2107 // int t1 = timer_get_milliseconds();
2110 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2112 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2115 // verify that he has a valid weapons.tbl
2116 verify_weapons_tbl();
2118 // Output version numbers to registry for auto patching purposes
2119 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2120 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2121 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2123 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2124 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2125 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2128 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2132 Asteroids_enabled = 1;
2135 /////////////////////////////
2137 /////////////////////////////
2142 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2143 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2145 if (!stricmp(ptr, NOX("no sound"))) {
2146 Cmdline_freespace_no_sound = 1;
2148 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2150 } else if (!stricmp(ptr, NOX("EAX"))) {
2155 if (!Is_standalone) {
2156 snd_init(use_a3d, use_eax);
2158 /////////////////////////////
2160 /////////////////////////////
2162 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2165 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);
2167 // fire up the UpdateLauncher executable
2169 PROCESS_INFORMATION pi;
2171 memset( &si, 0, sizeof(STARTUPINFO) );
2174 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2175 NULL, // pointer to command line string
2176 NULL, // pointer to process security attributes
2177 NULL, // pointer to thread security attributes
2178 FALSE, // handle inheritance flag
2179 CREATE_DEFAULT_ERROR_MODE, // creation flags
2180 NULL, // pointer to new environment block
2181 NULL, // pointer to current directory name
2182 &si, // pointer to STARTUPINFO
2183 &pi // pointer to PROCESS_INFORMATION
2186 // If the Launcher could not be started up, let the user know
2188 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2197 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2199 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);
2207 // check for hi res pack file
2208 int has_sparky_hi = 0;
2210 // check if sparky_hi exists -- access mode 0 means does file exist
2213 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2216 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2219 // see if we've got 32 bit in the string
2220 if(strstr(ptr, "32 bit")){
2227 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2229 // always 640 for E3
2230 gr_init(GR_640, GR_GLIDE);
2232 // regular or hi-res ?
2234 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2236 if(strstr(ptr, NOX("(1024x768)"))){
2238 gr_init(GR_1024, GR_GLIDE);
2240 gr_init(GR_640, GR_GLIDE);
2243 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2245 // always 640 for E3
2247 gr_init(GR_640, GR_DIRECT3D, depth);
2249 // regular or hi-res ?
2251 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2253 if(strstr(ptr, NOX("(1024x768)"))){
2257 gr_init(GR_1024, GR_DIRECT3D, depth);
2261 gr_init(GR_640, GR_DIRECT3D, depth);
2267 if ( Use_fullscreen_at_startup && !Is_standalone) {
2268 gr_init(GR_640, GR_DIRECTDRAW);
2270 gr_init(GR_640, GR_SOFTWARE);
2273 if ( !Is_standalone ) {
2274 gr_init(GR_640, GR_DIRECTDRAW);
2276 gr_init(GR_640, GR_SOFTWARE);
2281 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2282 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2283 gr_init(GR_1024, GR_OPENGL);
2285 gr_init(GR_640, GR_OPENGL);
2289 gr_init(GR_640, GR_SOFTWARE);
2294 extern int Gr_inited;
2295 if(trying_d3d && !Gr_inited){
2296 extern char Device_init_error[512];
2298 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2307 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2308 Freespace_gamma = (float)atof(ptr);
2309 if ( Freespace_gamma == 0.0f ) {
2310 Freespace_gamma = 1.80f;
2311 } else if ( Freespace_gamma < 0.1f ) {
2312 Freespace_gamma = 0.1f;
2313 } else if ( Freespace_gamma > 5.0f ) {
2314 Freespace_gamma = 5.0f;
2316 char tmp_gamma_string[32];
2317 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2318 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2320 gr_set_gamma(Freespace_gamma);
2322 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2325 display_title_screen();
2329 // attempt to load up master tracker registry info (login and password)
2330 Multi_tracker_id = -1;
2332 // pxo login and password
2333 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2335 nprintf(("Network","Error reading in PXO login data\n"));
2336 strcpy(Multi_tracker_login,"");
2338 strcpy(Multi_tracker_login,ptr);
2340 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2342 nprintf(("Network","Error reading PXO password\n"));
2343 strcpy(Multi_tracker_passwd,"");
2345 strcpy(Multi_tracker_passwd,ptr);
2348 // pxo squad name and password
2349 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2351 nprintf(("Network","Error reading in PXO squad name\n"));
2352 strcpy(Multi_tracker_squad_name, "");
2354 strcpy(Multi_tracker_squad_name, ptr);
2357 // If less than 48MB of RAM, use low memory model.
2358 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2359 mprintf(( "Using normal memory settings...\n" ));
2360 bm_set_low_mem(1); // Use every other frame of bitmaps
2362 mprintf(( "Using high memory settings...\n" ));
2363 bm_set_low_mem(0); // Use all frames of bitmaps
2366 // load non-darkening pixel defs
2367 palman_load_pixels();
2369 // hud shield icon stuff
2370 hud_shield_game_init();
2372 control_config_common_init(); // sets up localization stuff in the control config
2378 gamesnd_parse_soundstbl();
2383 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2388 player_controls_init();
2391 //if(!Is_standalone){
2399 ship_init(); // read in ships.tbl
2401 mission_campaign_init(); // load in the default campaign
2403 // navmap_init(); // init the navigation map system
2404 context_help_init();
2405 techroom_intel_init(); // parse species.tbl, load intel info
2407 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2408 init_animating_pointer();
2410 mission_brief_common_init(); // Mark all the briefing structures as empty.
2411 gr_font_init(); // loads up all fonts
2413 neb2_init(); // fullneb stuff
2417 player_tips_init(); // helpful tips
2420 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2421 pilot_load_pic_list();
2422 pilot_load_squad_pic_list();
2424 load_animating_pointer(NOX("cursor"), 0, 0);
2426 // initialize alpha colors
2427 alpha_colors_init();
2430 // Game_music_paused = 0;
2437 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2438 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2440 mprintf(("cfile_init() took %d\n", e1 - s1));
2441 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2444 char transfer_text[128];
2446 float Start_time = 0.0f;
2448 float Framerate = 0.0f;
2450 float Timing_total = 0.0f;
2451 float Timing_render2 = 0.0f;
2452 float Timing_render3 = 0.0f;
2453 float Timing_flip = 0.0f;
2454 float Timing_clear = 0.0f;
2456 MONITOR(NumPolysDrawn);
2462 void game_get_framerate()
2464 char text[128] = "";
2466 if ( frame_int == -1 ) {
2468 for (i=0; i<FRAME_FILTER; i++ ) {
2469 frametimes[i] = 0.0f;
2474 frametotal -= frametimes[frame_int];
2475 frametotal += flFrametime;
2476 frametimes[frame_int] = flFrametime;
2477 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2479 if ( frametotal != 0.0 ) {
2480 if ( Framecount >= FRAME_FILTER )
2481 Framerate = FRAME_FILTER / frametotal;
2483 Framerate = Framecount / frametotal;
2484 sprintf( text, NOX("FPS: %.1f"), Framerate );
2486 sprintf( text, NOX("FPS: ?") );
2490 if (Show_framerate) {
2491 gr_set_color_fast(&HUD_color_debug);
2492 gr_string( 570, 2, text );
2496 void game_show_framerate()
2500 cur_time = f2fl(timer_get_approx_seconds());
2501 if (cur_time - Start_time > 30.0f) {
2502 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2503 Start_time += 1000.0f;
2506 //mprintf(( "%s\n", text ));
2509 if ( Debug_dump_frames )
2513 // possibly show control checking info
2514 control_check_indicate();
2516 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2517 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2518 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2519 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2522 if ( Show_cpu == 1 ) {
2527 dy = gr_get_font_height() + 1;
2529 gr_set_color_fast(&HUD_color_debug);
2533 extern int D3D_textures_in;
2534 extern int D3D_textures_in_frame;
2535 extern int Glide_textures_in;
2536 extern int Glide_textures_in_frame;
2537 extern int Glide_explosion_vram;
2538 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2540 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2542 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2548 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2550 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2552 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2554 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2556 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2561 extern int Num_pairs; // Number of object pairs that were checked.
2562 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2565 extern int Num_pairs_checked; // What percent of object pairs were checked.
2566 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2568 Num_pairs_checked = 0;
2572 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2575 if ( Timing_total > 0.01f ) {
2576 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2578 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2580 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2582 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2584 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2594 dy = gr_get_font_height() + 1;
2596 gr_set_color_fast(&HUD_color_debug);
2599 extern int TotalRam;
2600 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2605 extern int Model_ram;
2606 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2610 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2612 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2614 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2618 extern int D3D_textures_in;
2619 extern int Glide_textures_in;
2620 extern int Glide_textures_in_frame;
2621 extern int Glide_explosion_vram;
2622 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2624 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2626 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2635 if ( Show_player_pos ) {
2639 gr_printf(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.x), fl2i(Player_obj->pos.y), fl2i(Player_obj->pos.z));
2642 MONITOR_INC(NumPolys, modelstats_num_polys);
2643 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2644 MONITOR_INC(NumVerts, modelstats_num_verts );
2646 modelstats_num_polys = 0;
2647 modelstats_num_polys_drawn = 0;
2648 modelstats_num_verts = 0;
2649 modelstats_num_sortnorms = 0;
2653 void game_show_standalone_framerate()
2655 float frame_rate=30.0f;
2656 if ( frame_int == -1 ) {
2658 for (i=0; i<FRAME_FILTER; i++ ) {
2659 frametimes[i] = 0.0f;
2664 frametotal -= frametimes[frame_int];
2665 frametotal += flFrametime;
2666 frametimes[frame_int] = flFrametime;
2667 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2669 if ( frametotal != 0.0 ) {
2670 if ( Framecount >= FRAME_FILTER ){
2671 frame_rate = FRAME_FILTER / frametotal;
2673 frame_rate = Framecount / frametotal;
2676 std_set_standalone_fps(frame_rate);
2680 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2681 void game_show_time_left()
2685 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2686 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2687 // checking how much time is left
2689 if ( Mission_end_time == -1 ){
2693 diff = f2i(Mission_end_time - Missiontime);
2694 // be sure to bash to 0. diff could be negative on frame that we quit mission
2699 hud_set_default_color();
2700 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2703 //========================================================================================
2704 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2705 //========================================================================================
2709 DCF(ai_pause,"Pauses ai")
2712 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2713 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2714 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2715 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2718 obj_init_all_ships_physics();
2721 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2722 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2725 DCF(single_step,"Single steps the game")
2728 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2729 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2730 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2731 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2733 last_single_step = 0; // Make so single step waits a frame before stepping
2736 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2737 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2740 DCF_BOOL(physics_pause, physics_paused)
2741 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2742 DCF_BOOL(ai_firing, Ai_firing_enabled )
2744 // Create some simple aliases to these commands...
2745 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2746 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2747 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2748 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2749 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2752 //========================================================================================
2753 //========================================================================================
2756 void game_training_pause_do()
2760 key = game_check_key();
2762 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2769 void game_increase_skill_level()
2772 if (Game_skill_level >= NUM_SKILL_LEVELS){
2773 Game_skill_level = 0;
2777 int Player_died_time;
2779 int View_percent = 100;
2782 DCF(view, "Sets the percent of the 3d view to render.")
2785 dc_get_arg(ARG_INT);
2786 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2787 View_percent = Dc_arg_int;
2789 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2795 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2799 dc_printf("View is set to %d%%\n", View_percent );
2804 // Set the clip region for the 3d rendering window
2805 void game_set_view_clip()
2807 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2808 // Set the clip region for the letterbox "dead view"
2809 int yborder = gr_screen.max_h/4;
2811 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2812 // J.S. I've changed my ways!! See the new "no constants" code!!!
2813 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2815 // Set the clip region for normal view
2816 if ( View_percent >= 100 ) {
2819 int xborder, yborder;
2821 if ( View_percent < 5 ) {
2825 float fp = i2fl(View_percent)/100.0f;
2826 int fi = fl2i(fl_sqrt(fp)*100.0f);
2827 if ( fi > 100 ) fi=100;
2829 xborder = ( gr_screen.max_w*(100-fi) )/200;
2830 yborder = ( gr_screen.max_h*(100-fi) )/200;
2832 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2838 void show_debug_stuff()
2841 int laser_count = 0, missile_count = 0;
2843 for (i=0; i<MAX_OBJECTS; i++) {
2844 if (Objects[i].type == OBJ_WEAPON){
2845 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2847 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2853 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2856 extern int Tool_enabled;
2861 int tst_bitmap = -1;
2863 float tst_offset, tst_offset_total;
2866 void game_tst_frame_pre()
2874 g3_rotate_vertex(&v, &tst_pos);
2875 g3_project_vertex(&v);
2878 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2882 // big ship? always tst
2884 // within 3000 meters
2885 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2889 // within 300 meters
2890 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2897 void game_tst_frame()
2907 tst_time = time(NULL);
2909 // load the tst bitmap
2910 switch((int)frand_range(0.0f, 3.0)){
2912 tst_bitmap = bm_load("ig_jim");
2914 mprintf(("TST 0\n"));
2918 tst_bitmap = bm_load("ig_kan");
2920 mprintf(("TST 1\n"));
2924 tst_bitmap = bm_load("ig_jim");
2926 mprintf(("TST 2\n"));
2930 tst_bitmap = bm_load("ig_kan");
2932 mprintf(("TST 3\n"));
2941 // get the tst bitmap dimensions
2943 bm_get_info(tst_bitmap, &w, &h);
2946 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2948 snd_play(&Snds[SND_VASUDAN_BUP]);
2950 // tst x and direction
2954 tst_offset_total = (float)w;
2955 tst_offset = (float)w;
2957 tst_x = (float)gr_screen.max_w;
2958 tst_offset_total = (float)-w;
2959 tst_offset = (float)w;
2967 float diff = (tst_offset_total / 0.5f) * flFrametime;
2973 tst_offset -= fl_abs(diff);
2974 } else if(tst_mode == 2){
2977 tst_offset -= fl_abs(diff);
2981 gr_set_bitmap(tst_bitmap);
2982 gr_bitmap((int)tst_x, (int)tst_y);
2985 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2989 // if we passed the switch point
2990 if(tst_offset <= 0.0f){
2995 tst_stamp = timestamp(1000);
2996 tst_offset = fl_abs(tst_offset_total);
3007 void game_tst_mark(object *objp, ship *shipp)
3016 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3019 sip = &Ship_info[shipp->ship_info_index];
3026 tst_pos = objp->pos;
3027 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3033 extern void render_shields();
3035 void player_repair_frame(float frametime)
3037 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3039 for(idx=0;idx<MAX_PLAYERS;idx++){
3042 np = &Net_players[idx];
3044 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)){
3046 // don't rearm/repair if the player is dead or dying/departing
3047 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3048 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3053 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3054 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3060 #define NUM_FRAMES_TEST 300
3061 #define NUM_MIXED_SOUNDS 16
3062 void do_timing_test(float flFrametime)
3064 static int framecount = 0;
3065 static int test_running = 0;
3066 static float test_time = 0.0f;
3068 static int snds[NUM_MIXED_SOUNDS];
3071 if ( test_running ) {
3073 test_time += flFrametime;
3074 if ( framecount >= NUM_FRAMES_TEST ) {
3076 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3077 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3082 if ( Test_begin == 1 ) {
3088 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3091 // start looping digital sounds
3092 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3093 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3100 DCF(dcf_fov, "Change the field of view")
3103 dc_get_arg(ARG_FLOAT|ARG_NONE);
3104 if ( Dc_arg_type & ARG_NONE ) {
3105 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3106 dc_printf( "Zoom factor reset\n" );
3108 if ( Dc_arg_type & ARG_FLOAT ) {
3109 if (Dc_arg_float < 0.25f) {
3110 Viewer_zoom = 0.25f;
3111 dc_printf("Zoom factor pinned at 0.25.\n");
3112 } else if (Dc_arg_float > 1.25f) {
3113 Viewer_zoom = 1.25f;
3114 dc_printf("Zoom factor pinned at 1.25.\n");
3116 Viewer_zoom = Dc_arg_float;
3122 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3125 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3129 DCF(framerate_cap, "Sets the framerate cap")
3132 dc_get_arg(ARG_INT);
3133 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3134 Framerate_cap = Dc_arg_int;
3136 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3142 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3143 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3144 dc_printf("[n] must be from 1 to 120.\n");
3148 if ( Framerate_cap )
3149 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3151 dc_printf("There is no framerate cap currently active.\n");
3155 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3156 int Show_viewing_from_self = 0;
3158 void say_view_target()
3160 object *view_target;
3162 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3163 view_target = &Objects[Player_ai->target_objnum];
3165 view_target = Player_obj;
3167 if (Game_mode & GM_DEAD) {
3168 if (Player_ai->target_objnum != -1)
3169 view_target = &Objects[Player_ai->target_objnum];
3172 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3173 if (view_target != Player_obj){
3175 char *view_target_name = NULL;
3176 switch(Objects[Player_ai->target_objnum].type) {
3178 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3181 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3182 Viewer_mode &= ~VM_OTHER_SHIP;
3184 case OBJ_JUMP_NODE: {
3185 char jump_node_name[128];
3186 strcpy(jump_node_name, XSTR( "jump node", 184));
3187 view_target_name = jump_node_name;
3188 Viewer_mode &= ~VM_OTHER_SHIP;
3197 if ( view_target_name ) {
3198 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3199 Show_viewing_from_self = 1;
3202 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3203 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3204 Show_viewing_from_self = 1;
3206 if (Show_viewing_from_self)
3207 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3212 Last_view_target = view_target;
3216 float Game_hit_x = 0.0f;
3217 float Game_hit_y = 0.0f;
3219 // Reset at the beginning of each frame
3220 void game_whack_reset()
3226 // Apply a 2d whack to the player
3227 void game_whack_apply( float x, float y )
3229 // Do some force feedback
3230 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3236 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3239 // call to apply a "shudder"
3240 void game_shudder_apply(int time, float intensity)
3242 Game_shudder_time = timestamp(time);
3243 Game_shudder_total = time;
3244 Game_shudder_intensity = intensity;
3247 #define FF_SCALE 10000
3248 void apply_hud_shake(matrix *eye_orient)
3250 if (Viewer_obj == Player_obj) {
3251 physics_info *pi = &Player_obj->phys_info;
3259 // Make eye shake due to afterburner
3260 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3263 dtime = timestamp_until(pi->afterburner_decay);
3267 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3268 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3271 // Make eye shake due to engine wash
3273 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3276 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3277 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3279 // get the intensity
3280 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3284 vm_vec_rand_vec_quick(&rand_vec);
3287 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3291 // make hud shake due to shuddering
3292 if(Game_shudder_time != -1){
3293 // if the timestamp has elapsed
3294 if(timestamp_elapsed(Game_shudder_time)){
3295 Game_shudder_time = -1;
3297 // otherwise apply some shudder
3301 dtime = timestamp_until(Game_shudder_time);
3305 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));
3306 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));
3311 vm_angles_2_matrix(&tm, &tangles);
3312 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3313 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3314 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3315 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3320 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3322 // Player's velocity just before he blew up. Used to keep camera target moving.
3323 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3325 // Set eye_pos and eye_orient based on view mode.
3326 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3330 static int last_Viewer_mode = 0;
3331 static int last_Game_mode = 0;
3332 static int last_Viewer_objnum = -1;
3334 // This code is supposed to detect camera "cuts"... like going between
3337 // determine if we need to regenerate the nebula
3338 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3339 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3340 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3341 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3342 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3343 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3344 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3345 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3346 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3349 // regenerate the nebula
3353 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3354 //mprintf(( "************** Camera cut! ************\n" ));
3355 last_Viewer_mode = Viewer_mode;
3356 last_Game_mode = Game_mode;
3358 // Camera moved. Tell stars & debris to not do blurring.
3364 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3365 player_display_packlock_view();
3368 game_set_view_clip();
3370 if (Game_mode & GM_DEAD) {
3371 vector vec_to_deader, view_pos;
3374 Viewer_mode |= VM_DEAD_VIEW;
3376 if (Player_ai->target_objnum != -1) {
3377 int view_from_player = 1;
3379 if (Viewer_mode & VM_OTHER_SHIP) {
3380 // View from target.
3381 Viewer_obj = &Objects[Player_ai->target_objnum];
3383 last_Viewer_objnum = Player_ai->target_objnum;
3385 if ( Viewer_obj->type == OBJ_SHIP ) {
3386 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3387 view_from_player = 0;
3390 last_Viewer_objnum = -1;
3393 if ( view_from_player ) {
3394 // View target from player ship.
3396 *eye_pos = Player_obj->pos;
3397 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3398 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3401 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3403 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3404 dist += flFrametime * 16.0f;
3406 vm_vec_scale(&vec_to_deader, -dist);
3407 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3409 view_pos = Player_obj->pos;
3411 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3412 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3413 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3414 Dead_player_last_vel = Player_obj->phys_info.vel;
3415 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.x, Player_obj->phys_info.vel.y, Player_obj->phys_info.vel.z));
3416 } else if (Player_ai->target_objnum != -1) {
3417 view_pos = Objects[Player_ai->target_objnum].pos;
3419 // Make camera follow explosion, but gradually slow down.
3420 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3421 view_pos = Player_obj->pos;
3422 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3423 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3426 *eye_pos = Dead_camera_pos;
3428 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3430 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3435 // if supernova shockwave
3436 if(supernova_camera_cut()){
3440 // call it dead view
3441 Viewer_mode |= VM_DEAD_VIEW;
3443 // set eye pos and orient
3444 supernova_set_view(eye_pos, eye_orient);
3446 // If already blown up, these other modes can override.
3447 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3448 Viewer_mode &= ~VM_DEAD_VIEW;
3450 Viewer_obj = Player_obj;
3452 if (Viewer_mode & VM_OTHER_SHIP) {
3453 if (Player_ai->target_objnum != -1){
3454 Viewer_obj = &Objects[Player_ai->target_objnum];
3455 last_Viewer_objnum = Player_ai->target_objnum;
3457 Viewer_mode &= ~VM_OTHER_SHIP;
3458 last_Viewer_objnum = -1;
3461 last_Viewer_objnum = -1;
3464 if (Viewer_mode & VM_EXTERNAL) {
3467 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3468 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3470 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3472 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3473 vm_vec_normalize(&eye_dir);
3474 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3477 // Modify the orientation based on head orientation.
3478 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3480 } else if ( Viewer_mode & VM_CHASE ) {
3483 if ( Viewer_obj->phys_info.speed < 0.1 )
3484 move_dir = Viewer_obj->orient.fvec;
3486 move_dir = Viewer_obj->phys_info.vel;
3487 vm_vec_normalize(&move_dir);
3490 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3491 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3492 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3493 vm_vec_normalize(&eye_dir);
3495 // JAS: I added the following code because if you slew up using
3496 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3497 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3498 // call because the up and the forward vector are the same. I fixed
3499 // it by adding in a fraction of the right vector all the time to the
3501 vector tmp_up = Viewer_obj->orient.uvec;
3502 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3504 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3507 // Modify the orientation based on head orientation.
3508 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3509 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3510 *eye_pos = Camera_pos;
3512 ship * shipp = &Ships[Player_obj->instance];
3514 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3515 vm_vec_normalize(&eye_dir);
3516 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3519 // get an eye position based upon the correct type of object
3520 switch(Viewer_obj->type){
3522 // make a call to get the eye point for the player object
3523 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3526 // make a call to get the eye point for the player object
3527 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3533 #ifdef JOHNS_DEBUG_CODE
3534 john_debug_stuff(&eye_pos, &eye_orient);
3540 apply_hud_shake(eye_orient);
3542 // setup neb2 rendering
3543 neb2_render_setup(eye_pos, eye_orient);
3547 extern void ai_debug_render_stuff();
3550 int Game_subspace_effect = 0;
3551 DCF_BOOL( subspace, Game_subspace_effect );
3553 // Does everything needed to render a frame
3554 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3558 g3_start_frame(game_zbuffer);
3559 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3561 // maybe offset the HUD (jitter stuff)
3562 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3563 HUD_set_offsets(Viewer_obj, !dont_offset);
3565 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3566 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3567 // must be done before ships are rendered
3568 if ( MULTIPLAYER_CLIENT ) {
3569 shield_point_multi_setup();
3572 if ( Game_subspace_effect ) {
3573 stars_draw(0,0,0,1);
3575 stars_draw(1,1,1,0);
3578 obj_render_all(obj_render);
3579 beam_render_all(); // render all beam weapons
3580 particle_render_all(); // render particles after everything else.
3581 trail_render_all(); // render missilie trails after everything else.
3582 mflash_render_all(); // render all muzzle flashes
3584 // Why do we not show the shield effect in these modes? Seems ok.
3585 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3589 // render nebula lightning
3592 // render local player nebula
3593 neb2_render_player();
3596 ai_debug_render_stuff();
3599 #ifndef RELEASE_REAL
3600 // game_framerate_check();
3604 extern void snd_spew_debug_info();
3605 snd_spew_debug_info();
3608 //================ END OF 3D RENDERING STUFF ====================
3612 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3613 hud_maybe_clear_head_area();
3614 anim_render_all(0, flFrametime);
3617 extern int Multi_display_netinfo;
3618 if(Multi_display_netinfo){
3619 extern void multi_display_netinfo();
3620 multi_display_netinfo();
3623 game_tst_frame_pre();
3626 do_timing_test(flFrametime);
3630 extern int OO_update_index;
3631 multi_rate_display(OO_update_index, 375, 0);
3636 extern void oo_display();
3643 //#define JOHNS_DEBUG_CODE 1
3645 #ifdef JOHNS_DEBUG_CODE
3646 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3648 //if ( keyd_pressed[KEY_LSHIFT] )
3650 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3652 model_subsystem *turret = tsys->system_info;
3654 if (turret->type == SUBSYSTEM_TURRET ) {
3656 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3658 ship_model_start(tobj);
3660 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3661 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3662 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3664 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3666 ship_model_stop(tobj);
3676 // following function for dumping frames for purposes of building trailers.
3679 // function to toggle state of dumping every frame into PCX when playing the game
3680 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3684 if ( Debug_dump_frames == 0 ) {
3686 Debug_dump_frames = 15;
3687 Debug_dump_trigger = 0;
3688 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3689 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3692 Debug_dump_frames = 0;
3693 Debug_dump_trigger = 0;
3694 gr_dump_frame_stop();
3695 dc_printf( "Frame dumping is now OFF\n" );
3701 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3705 if ( Debug_dump_frames == 0 ) {
3707 Debug_dump_frames = 15;
3708 Debug_dump_trigger = 1;
3709 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3710 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3713 Debug_dump_frames = 0;
3714 Debug_dump_trigger = 0;
3715 gr_dump_frame_stop();
3716 dc_printf( "Frame dumping is now OFF\n" );
3722 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3726 if ( Debug_dump_frames == 0 ) {
3728 Debug_dump_frames = 30;
3729 Debug_dump_trigger = 0;
3730 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3731 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3734 Debug_dump_frames = 0;
3735 Debug_dump_trigger = 0;
3736 gr_dump_frame_stop();
3737 dc_printf( "Frame dumping is now OFF\n" );
3743 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3747 if ( Debug_dump_frames == 0 ) {
3749 Debug_dump_frames = 30;
3750 Debug_dump_trigger = 1;
3751 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3752 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3755 Debug_dump_frames = 0;
3756 Debug_dump_trigger = 0;
3757 gr_dump_frame_stop();
3758 dc_printf( "Triggered frame dumping is now OFF\n" );
3764 void game_maybe_dump_frame()
3766 if ( !Debug_dump_frames ){
3770 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3777 Debug_dump_frame_num++;
3783 extern int Player_dead_state;
3785 // Flip the page and time how long it took.
3786 void game_flip_page_and_time_it()
3790 t1 = timer_get_fixed_seconds();
3792 t2 = timer_get_fixed_seconds();
3794 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3795 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3798 void game_simulation_frame()
3800 // blow ships up in multiplayer dogfight
3801 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){
3802 // blow up all non-player ships
3803 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3806 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3808 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)){
3809 moveup = GET_NEXT(moveup);
3812 shipp = &Ships[Objects[moveup->objnum].instance];
3813 sip = &Ship_info[shipp->ship_info_index];
3815 // only blow up small ships
3816 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3817 // function to simply explode a ship where it is currently at
3818 ship_self_destruct( &Objects[moveup->objnum] );
3821 moveup = GET_NEXT(moveup);
3827 // process AWACS stuff - do this first thing
3830 // single player, set Player hits_this_frame to 0
3831 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3832 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3833 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3837 supernova_process();
3838 if(supernova_active() >= 5){
3842 // fire targeting lasers now so that
3843 // 1 - created this frame
3844 // 2 - collide this frame
3845 // 3 - render this frame
3846 // 4 - ignored and deleted next frame
3847 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3849 ship_process_targeting_lasers();
3851 // do this here so that it works for multiplayer
3853 // get viewer direction
3854 int viewer_direction = PHYSICS_VIEWER_REAR;
3856 if(Viewer_mode == 0){
3857 viewer_direction = PHYSICS_VIEWER_FRONT;
3859 if(Viewer_mode & VM_PADLOCK_UP){
3860 viewer_direction = PHYSICS_VIEWER_UP;
3862 else if(Viewer_mode & VM_PADLOCK_REAR){
3863 viewer_direction = PHYSICS_VIEWER_REAR;
3865 else if(Viewer_mode & VM_PADLOCK_LEFT){
3866 viewer_direction = PHYSICS_VIEWER_LEFT;
3868 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3869 viewer_direction = PHYSICS_VIEWER_RIGHT;
3872 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3874 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3877 #define VM_PADLOCK_UP (1 << 7)
3878 #define VM_PADLOCK_REAR (1 << 8)
3879 #define VM_PADLOCK_LEFT (1 << 9)
3880 #define VM_PADLOCK_RIGHT (1 << 10)
3882 // evaluate mission departures and arrivals before we process all objects.
3883 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3885 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3886 // ships/wing packets.
3887 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3888 mission_parse_eval_stuff();
3891 // if we're an observer, move ourselves seperately from the standard physics
3892 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3893 obj_observer_move(flFrametime);
3896 // move all the objects now
3897 obj_move_all(flFrametime);
3899 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3900 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3901 // ship_check_cargo_all();
3902 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3903 mission_eval_goals();
3907 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3908 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3909 training_check_objectives();
3912 // do all interpolation now
3913 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3914 // client side processing of warping in effect stages
3915 multi_do_client_warp(flFrametime);
3917 // client side movement of an observer
3918 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3919 obj_observer_move(flFrametime);
3922 // move all objects - does interpolation now as well
3923 obj_move_all(flFrametime);
3926 // only process the message queue when the player is "in" the game
3927 if ( !Pre_player_entry ){
3928 message_queue_process(); // process any messages send to the player
3931 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3932 message_maybe_distort(); // maybe distort incoming message if comms damaged
3933 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3934 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3935 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3938 if(!(Game_mode & GM_STANDALONE_SERVER)){
3939 // process some stuff every frame (before frame is rendered)
3940 emp_process_local();
3942 hud_update_frame(); // update hud systems
3944 if (!physics_paused) {
3945 // Move particle system
3946 particle_move_all(flFrametime);
3948 // Move missile trails
3949 trail_move_all(flFrametime);
3951 // process muzzle flashes
3952 mflash_process_all();
3954 // Flash the gun flashes
3955 shipfx_flash_do_frame(flFrametime);
3957 shockwave_move_all(flFrametime); // update all the shockwaves
3960 // subspace missile strikes
3963 obj_snd_do_frame(); // update the object-linked persistant sounds
3964 game_maybe_update_sound_environment();
3965 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3967 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3969 if ( Game_subspace_effect ) {
3970 game_start_subspace_ambient_sound();
3976 // Maybe render and process the dead-popup
3977 void game_maybe_do_dead_popup(float frametime)
3979 if ( popupdead_is_active() ) {
3981 int choice = popupdead_do_frame(frametime);
3983 if ( Game_mode & GM_NORMAL ) {
3987 if(game_do_cd_mission_check(Game_current_mission_filename)){
3988 gameseq_post_event(GS_EVENT_ENTER_GAME);
3990 gameseq_post_event(GS_EVENT_MAIN_MENU);
3995 gameseq_post_event(GS_EVENT_END_GAME);
4000 if(game_do_cd_mission_check(Game_current_mission_filename)){
4001 gameseq_post_event(GS_EVENT_START_GAME);
4003 gameseq_post_event(GS_EVENT_MAIN_MENU);
4007 // this should only happen during a red alert mission
4010 Assert(The_mission.red_alert);
4011 if(!The_mission.red_alert){
4013 if(game_do_cd_mission_check(Game_current_mission_filename)){
4014 gameseq_post_event(GS_EVENT_START_GAME);
4016 gameseq_post_event(GS_EVENT_MAIN_MENU);
4021 // choose the previous mission
4022 mission_campaign_previous_mission();
4024 if(game_do_cd_mission_check(Game_current_mission_filename)){
4025 gameseq_post_event(GS_EVENT_START_GAME);
4027 gameseq_post_event(GS_EVENT_MAIN_MENU);
4038 case POPUPDEAD_DO_MAIN_HALL:
4039 multi_quit_game(PROMPT_NONE,-1);
4042 case POPUPDEAD_DO_RESPAWN:
4043 multi_respawn_normal();
4044 event_music_player_respawn();
4047 case POPUPDEAD_DO_OBSERVER:
4048 multi_respawn_observer();
4049 event_music_player_respawn_as_observer();
4058 if ( leave_popup ) {
4064 // returns true if player is actually in a game_play stats
4065 int game_actually_playing()
4069 state = gameseq_get_state();
4070 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4076 // Draw the 2D HUD gauges
4077 void game_render_hud_2d()
4079 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4083 HUD_render_2d(flFrametime);
4087 // Draw the 3D-dependant HUD gauges
4088 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4090 g3_start_frame(0); // 0 = turn zbuffering off
4091 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4093 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4094 HUD_render_3d(flFrametime);
4098 game_sunspot_process(flFrametime);
4100 // Diminish the palette effect
4101 game_flash_diminish(flFrametime);
4109 int actually_playing;
4110 fix total_time1, total_time2;
4111 fix render2_time1=0, render2_time2=0;
4112 fix render3_time1=0, render3_time2=0;
4113 fix flip_time1=0, flip_time2=0;
4114 fix clear_time1=0, clear_time2=0;
4120 if (Framerate_delay) {
4121 int start_time = timer_get_milliseconds();
4122 while (timer_get_milliseconds() < start_time + Framerate_delay)
4128 demo_do_frame_start();
4130 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4135 // start timing frame
4136 timing_frame_start();
4138 total_time1 = timer_get_fixed_seconds();
4140 // var to hold which state we are in
4141 actually_playing = game_actually_playing();
4143 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4144 if (!(Game_mode & GM_STANDALONE_SERVER)){
4145 Assert( OBJ_INDEX(Player_obj) >= 0 );
4149 if (Missiontime > Entry_delay_time){
4150 Pre_player_entry = 0;
4152 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4155 // Note: These are done even before the player enters, else buffers can overflow.
4156 if (! (Game_mode & GM_STANDALONE_SERVER)){
4160 shield_frame_init();
4162 if ( Player->control_mode != PCM_NORMAL )
4165 if ( !Pre_player_entry && actually_playing ) {
4166 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4168 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4169 game_process_keys();
4171 // don't read flying controls if we're playing a demo back
4172 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4173 read_player_controls( Player_obj, flFrametime);
4177 // if we're not the master, we may have to send the server-critical ship status button_info bits
4178 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4179 multi_maybe_send_ship_status();
4184 // Reset the whack stuff
4187 // These two lines must be outside of Pre_player_entry code,
4188 // otherwise too many lights are added.
4191 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4195 game_simulation_frame();
4197 // if not actually in a game play state, then return. This condition could only be true in
4198 // a multiplayer game.
4199 if ( !actually_playing ) {
4200 Assert( Game_mode & GM_MULTIPLAYER );
4204 if (!Pre_player_entry) {
4205 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4206 clear_time1 = timer_get_fixed_seconds();
4207 // clear the screen to black
4209 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4213 clear_time2 = timer_get_fixed_seconds();
4214 render3_time1 = timer_get_fixed_seconds();
4215 game_render_frame_setup(&eye_pos, &eye_orient);
4216 game_render_frame( &eye_pos, &eye_orient );
4218 // save the eye position and orientation
4219 if ( Game_mode & GM_MULTIPLAYER ) {
4220 Net_player->s_info.eye_pos = eye_pos;
4221 Net_player->s_info.eye_orient = eye_orient;
4224 hud_show_target_model();
4226 // check to see if we should display the death died popup
4227 if(Game_mode & GM_DEAD_BLEW_UP){
4228 if(Game_mode & GM_MULTIPLAYER){
4229 // catch the situation where we're supposed to be warping out on this transition
4230 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4231 gameseq_post_event(GS_EVENT_DEBRIEF);
4232 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4233 Player_died_popup_wait = -1;
4237 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4238 Player_died_popup_wait = -1;
4244 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4245 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4246 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4247 if(!popupdead_is_active()){
4251 Player_multi_died_check = -1;
4255 render3_time2 = timer_get_fixed_seconds();
4256 render2_time1 = timer_get_fixed_seconds();
4259 game_get_framerate();
4260 game_show_framerate();
4262 game_show_time_left();
4264 // Draw the 2D HUD gauges
4265 if(supernova_active() < 3){
4266 game_render_hud_2d();
4269 game_set_view_clip();
4271 // Draw 3D HUD gauges
4272 game_render_hud_3d(&eye_pos, &eye_orient);
4276 render2_time2 = timer_get_fixed_seconds();
4278 // maybe render and process the dead popup
4279 game_maybe_do_dead_popup(flFrametime);
4281 // start timing frame
4282 timing_frame_stop();
4283 // timing_display(30, 10);
4285 // If a regular popup is active, don't flip (popup code flips)
4286 if( !popup_running_state() ){
4287 flip_time1 = timer_get_fixed_seconds();
4288 game_flip_page_and_time_it();
4289 flip_time2 = timer_get_fixed_seconds();
4293 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4296 game_show_standalone_framerate();
4300 game_do_training_checks();
4303 // process lightning (nebula only)
4306 total_time2 = timer_get_fixed_seconds();
4308 // Got some timing numbers
4309 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4310 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4311 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4312 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4313 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4316 demo_do_frame_end();
4318 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4324 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4325 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4326 // died. This resulted in screwed up death sequences.
4328 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4329 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4330 static int timer_paused=0;
4331 #if defined(TIMER_TEST) && !defined(NDEBUG)
4332 static int stop_count,start_count;
4333 static int time_stopped,time_started;
4335 int saved_timestamp_ticker = -1;
4337 void game_reset_time()
4339 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4343 // Last_time = timer_get_fixed_seconds();
4349 void game_stop_time()
4351 if (timer_paused==0) {
4353 time = timer_get_fixed_seconds();
4354 // Save how much time progressed so far in the frame so we can
4355 // use it when we unpause.
4356 Last_delta_time = time - Last_time;
4358 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4359 if (Last_delta_time < 0) {
4360 #if defined(TIMER_TEST) && !defined(NDEBUG)
4361 Int3(); //get Matt!!!!
4363 Last_delta_time = 0;
4365 #if defined(TIMER_TEST) && !defined(NDEBUG)
4366 time_stopped = time;
4369 // Stop the timer_tick stuff...
4370 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4371 saved_timestamp_ticker = timestamp_ticker;
4375 #if defined(TIMER_TEST) && !defined(NDEBUG)
4380 void game_start_time()
4383 Assert(timer_paused >= 0);
4384 if (timer_paused==0) {
4386 time = timer_get_fixed_seconds();
4387 #if defined(TIMER_TEST) && !defined(NDEBUG)
4389 Int3(); //get Matt!!!!
4392 // Take current time, and set it backwards to account for time
4393 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4394 // will be correct when it goes to calculate the frametime next
4396 Last_time = time - Last_delta_time;
4397 #if defined(TIMER_TEST) && !defined(NDEBUG)
4398 time_started = time;
4401 // Restore the timer_tick stuff...
4402 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4403 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4404 timestamp_ticker = saved_timestamp_ticker;
4405 saved_timestamp_ticker = -1;
4408 #if defined(TIMER_TEST) && !defined(NDEBUG)
4414 void game_set_frametime(int state)
4417 float frame_cap_diff;
4419 thistime = timer_get_fixed_seconds();
4421 if ( Last_time == 0 )
4422 Frametime = F1_0 / 30;
4424 Frametime = thistime - Last_time;
4426 // Frametime = F1_0 / 30;
4428 fix debug_frametime = Frametime; // Just used to display frametime.
4430 // If player hasn't entered mission yet, make frame take 1/4 second.
4431 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4434 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4436 fix frame_speed = F1_0 / Debug_dump_frames;
4438 if (Frametime > frame_speed ){
4439 nprintf(("warning","slow frame: %x\n",Frametime));
4442 thistime = timer_get_fixed_seconds();
4443 Frametime = thistime - Last_time;
4444 } while (Frametime < frame_speed );
4446 Frametime = frame_speed;
4450 Assert( Framerate_cap > 0 );
4452 // Cap the framerate so it doesn't get too high.
4456 cap = F1_0/Framerate_cap;
4457 if (Frametime < cap) {
4458 thistime = cap - Frametime;
4459 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4460 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4462 thistime = timer_get_fixed_seconds();
4466 if((Game_mode & GM_STANDALONE_SERVER) &&
4467 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4469 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4470 Sleep((DWORD)(frame_cap_diff*1000));
4472 thistime += fl2f((frame_cap_diff));
4474 Frametime = thistime - Last_time;
4477 // If framerate is too low, cap it.
4478 if (Frametime > MAX_FRAMETIME) {
4480 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4482 // to remove warnings in release build
4483 debug_frametime = fl2f(flFrametime);
4485 Frametime = MAX_FRAMETIME;
4488 Frametime = fixmul(Frametime, Game_time_compression);
4490 Last_time = thistime;
4491 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4493 flFrametime = f2fl(Frametime);
4494 //if(!(Game_mode & GM_PLAYING_DEMO)){
4495 timestamp_inc(flFrametime);
4497 /* if ((Framecount > 0) && (Framecount < 10)) {
4498 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4503 // This is called from game_do_frame(), and from navmap_do_frame()
4504 void game_update_missiontime()
4506 // TODO JAS: Put in if and move this into game_set_frametime,
4507 // fix navmap to call game_stop/start_time
4508 //if ( !timer_paused )
4509 Missiontime += Frametime;
4512 void game_do_frame()
4514 game_set_frametime(GS_STATE_GAME_PLAY);
4515 game_update_missiontime();
4517 if (Game_mode & GM_STANDALONE_SERVER) {
4518 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4521 if ( game_single_step && (last_single_step == game_single_step) ) {
4522 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4523 while( key_checkch() == 0 )
4525 os_set_title( XSTR( "FreeSpace", 171) );
4526 Last_time = timer_get_fixed_seconds();
4529 last_single_step = game_single_step;
4531 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4532 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4536 Keep_mouse_centered = 0;
4537 monitor_update(); // Update monitor variables
4540 void multi_maybe_do_frame()
4542 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4547 int Joymouse_button_status = 0;
4549 // Flush all input devices
4557 Joymouse_button_status = 0;
4559 //mprintf(("Game flush!\n" ));
4562 // function for multiplayer only which calls game_do_state_common() when running the
4564 void game_do_dc_networking()
4566 Assert( Game_mode & GM_MULTIPLAYER );
4568 game_do_state_common( gameseq_get_state() );
4571 // Call this whenever in a loop, or when you need to check for a keystroke.
4572 int game_check_key()
4578 // convert keypad enter to normal enter
4579 if ((k & KEY_MASK) == KEY_PADENTER)
4580 k = (k & ~KEY_MASK) | KEY_ENTER;
4587 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4588 static int Demo_show_trailer_timestamp = 0;
4590 void demo_reset_trailer_timer()
4592 Demo_show_trailer_timestamp = timer_get_milliseconds();
4595 void demo_maybe_show_trailer(int k)
4598 // if key pressed, reset demo trailer timer
4600 demo_reset_trailer_timer();
4604 // if mouse moved, reset demo trailer timer
4607 mouse_get_delta(&dx, &dy);
4608 if ( (dx > 0) || (dy > 0) ) {
4609 demo_reset_trailer_timer();
4613 // if joystick has moved, reset demo trailer timer
4616 joy_get_delta(&dx, &dy);
4617 if ( (dx > 0) || (dy > 0) ) {
4618 demo_reset_trailer_timer();
4622 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4623 // the low-level code. Ugly, I know... but was the simplest and most
4626 // if 30 seconds since last demo trailer time reset, launch movie
4627 if ( os_foreground() ) {
4628 int now = timer_get_milliseconds();
4629 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4630 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4632 movie_play( NOX("fstrailer2.mve") );
4633 demo_reset_trailer_timer();
4641 // same as game_check_key(), except this is used while actually in the game. Since there
4642 // generally are differences between game control keys and general UI keys, makes sense to
4643 // have seperate functions for each case. If you are not checking a game control while in a
4644 // mission, you should probably be using game_check_key() instead.
4649 if (!os_foreground()) {
4654 // If we're in a single player game, pause it.
4655 if (!(Game_mode & GM_MULTIPLAYER)){
4656 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4657 game_process_pause_key();
4665 demo_maybe_show_trailer(k);
4668 // Move the mouse cursor with the joystick.
4669 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4670 // Move the mouse cursor with the joystick
4674 joy_get_pos( &jx, &jy, &jz, &jr );
4676 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4677 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4680 mouse_get_real_pos( &mx, &my );
4681 mouse_set_pos( mx+dx, my+dy );
4686 m = mouse_down(MOUSE_LEFT_BUTTON);
4688 if ( j != Joymouse_button_status ) {
4689 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4690 Joymouse_button_status = j;
4692 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4693 } else if ( (!j) && (m) ) {
4694 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4699 // if we should be ignoring keys because of some multiplayer situations
4700 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4704 // If a popup is running, don't process all the Fn keys
4705 if( popup_active() ) {
4709 state = gameseq_get_state();
4711 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4714 case KEY_DEBUGGED + KEY_BACKSP:
4719 launch_context_help();
4724 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4726 // don't allow f2 while warping out in multiplayer
4727 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4732 case GS_STATE_INITIAL_PLAYER_SELECT:
4733 case GS_STATE_OPTIONS_MENU:
4734 case GS_STATE_HUD_CONFIG:
4735 case GS_STATE_CONTROL_CONFIG:
4736 case GS_STATE_DEATH_DIED:
4737 case GS_STATE_DEATH_BLEW_UP:
4738 case GS_STATE_VIEW_MEDALS:
4742 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4749 // hotkey selection screen -- only valid from briefing and beyond.
4752 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) ) {
4753 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4759 case KEY_DEBUGGED + KEY_F3:
4760 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4763 case KEY_DEBUGGED + KEY_F4:
4764 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4768 if(Game_mode & GM_MULTIPLAYER){
4769 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4770 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4774 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4775 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4781 case KEY_ESC | KEY_SHIFTED:
4782 // make sure to quit properly out of multiplayer
4783 if(Game_mode & GM_MULTIPLAYER){
4784 multi_quit_game(PROMPT_NONE);
4787 gameseq_post_event( GS_EVENT_QUIT_GAME );
4792 case KEY_DEBUGGED + KEY_P:
4795 case KEY_PRINT_SCRN:
4797 static int counter = 0;
4802 sprintf( tmp_name, NOX("screen%02d"), counter );
4804 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4805 gr_print_screen(tmp_name);
4813 case KEY_SHIFTED | KEY_ENTER: {
4815 #if !defined(NDEBUG)
4817 if ( Game_mode & GM_NORMAL ){
4821 // if we're in multiplayer mode, do some special networking
4822 if(Game_mode & GM_MULTIPLAYER){
4823 debug_console(game_do_dc_networking);
4830 if ( Game_mode & GM_NORMAL )
4844 gameseq_post_event(GS_EVENT_QUIT_GAME);
4847 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4850 void camera_set_position( vector *pos )
4855 void camera_set_orient( matrix *orient )
4857 Camera_orient = *orient;
4860 void camera_set_velocity( vector *vel, int instantaneous )
4862 Camera_desired_velocity.x = 0.0f;
4863 Camera_desired_velocity.y = 0.0f;
4864 Camera_desired_velocity.z = 0.0f;
4866 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4867 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4868 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4870 if ( instantaneous ) {
4871 Camera_velocity = Camera_desired_velocity;
4879 vector new_vel, delta_pos;
4881 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4882 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4883 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4885 Camera_velocity = new_vel;
4887 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4889 vm_vec_add2( &Camera_pos, &delta_pos );
4891 float ot = Camera_time+0.0f;
4893 Camera_time += flFrametime;
4895 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4898 tmp.z = 4.739f; // always go this fast forward.
4900 // pick x and y velocities so they are always on a
4901 // circle with a 25 m radius.
4903 float tmp_angle = frand()*PI2;
4905 tmp.x = 22.0f * (float)sin(tmp_angle);
4906 tmp.y = -22.0f * (float)cos(tmp_angle);
4908 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4910 //mprintf(( "Changing velocity!\n" ));
4911 camera_set_velocity( &tmp, 0 );
4914 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4915 vector tmp = { 0.0f, 0.0f, 0.0f };
4916 camera_set_velocity( &tmp, 0 );
4921 void end_demo_campaign_do()
4923 #if defined(FS2_DEMO)
4924 // show upsell screens
4925 demo_upsell_show_screens();
4926 #elif defined(OEM_BUILD)
4927 // show oem upsell screens
4928 oem_upsell_show_screens();
4931 // drop into main hall
4932 gameseq_post_event( GS_EVENT_MAIN_MENU );
4935 // All code to process events. This is the only place
4936 // that you should change the state of the game.
4937 void game_process_event( int current_state, int event )
4939 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4942 case GS_EVENT_SIMULATOR_ROOM:
4943 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4946 case GS_EVENT_MAIN_MENU:
4947 gameseq_set_state(GS_STATE_MAIN_MENU);
4950 case GS_EVENT_OPTIONS_MENU:
4951 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4954 case GS_EVENT_BARRACKS_MENU:
4955 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4958 case GS_EVENT_TECH_MENU:
4959 gameseq_set_state(GS_STATE_TECH_MENU);
4962 case GS_EVENT_TRAINING_MENU:
4963 gameseq_set_state(GS_STATE_TRAINING_MENU);
4966 case GS_EVENT_START_GAME:
4967 Select_default_ship = 0;
4968 Player_multi_died_check = -1;
4969 gameseq_set_state(GS_STATE_CMD_BRIEF);
4972 case GS_EVENT_START_BRIEFING:
4973 gameseq_set_state(GS_STATE_BRIEFING);
4976 case GS_EVENT_DEBRIEF:
4977 // did we end the campaign in the main freespace 2 single player campaign?
4978 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4979 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4981 gameseq_set_state(GS_STATE_DEBRIEF);
4984 Player_multi_died_check = -1;
4987 case GS_EVENT_SHIP_SELECTION:
4988 gameseq_set_state( GS_STATE_SHIP_SELECT );
4991 case GS_EVENT_WEAPON_SELECTION:
4992 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4995 case GS_EVENT_ENTER_GAME:
4997 // maybe start recording a demo
4999 demo_start_record("test.fsd");
5003 if (Game_mode & GM_MULTIPLAYER) {
5004 // if we're respawning, make sure we change the view mode so that the hud shows up
5005 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5009 gameseq_set_state(GS_STATE_GAME_PLAY);
5011 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5014 Player_multi_died_check = -1;
5016 // clear multiplayer button info
5017 extern button_info Multi_ship_status_bi;
5018 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5020 Start_time = f2fl(timer_get_approx_seconds());
5022 mprintf(("Entering game at time = %7.3f\n", Start_time));
5026 case GS_EVENT_START_GAME_QUICK:
5027 Select_default_ship = 1;
5028 gameseq_post_event(GS_EVENT_ENTER_GAME);
5032 case GS_EVENT_END_GAME:
5033 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5034 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5035 gameseq_set_state(GS_STATE_MAIN_MENU);
5040 Player_multi_died_check = -1;
5043 case GS_EVENT_QUIT_GAME:
5044 main_hall_stop_music();
5045 main_hall_stop_ambient();
5046 gameseq_set_state(GS_STATE_QUIT_GAME);
5048 Player_multi_died_check = -1;
5051 case GS_EVENT_GAMEPLAY_HELP:
5052 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5055 case GS_EVENT_PAUSE_GAME:
5056 gameseq_push_state(GS_STATE_GAME_PAUSED);
5059 case GS_EVENT_DEBUG_PAUSE_GAME:
5060 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5063 case GS_EVENT_TRAINING_PAUSE:
5064 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5067 case GS_EVENT_PREVIOUS_STATE:
5068 gameseq_pop_state();
5071 case GS_EVENT_TOGGLE_FULLSCREEN:
5072 #ifndef HARDWARE_ONLY
5074 if ( gr_screen.mode == GR_SOFTWARE ) {
5075 gr_init( GR_640, GR_DIRECTDRAW );
5076 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5077 gr_init( GR_640, GR_SOFTWARE );
5083 case GS_EVENT_TOGGLE_GLIDE:
5085 if ( gr_screen.mode != GR_GLIDE ) {
5086 gr_init( GR_640, GR_GLIDE );
5088 gr_init( GR_640, GR_SOFTWARE );
5093 case GS_EVENT_LOAD_MISSION_MENU:
5094 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5097 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5098 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5101 case GS_EVENT_HUD_CONFIG:
5102 gameseq_push_state( GS_STATE_HUD_CONFIG );
5105 case GS_EVENT_CONTROL_CONFIG:
5106 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5109 case GS_EVENT_DEATH_DIED:
5110 gameseq_set_state( GS_STATE_DEATH_DIED );
5113 case GS_EVENT_DEATH_BLEW_UP:
5114 if ( current_state == GS_STATE_DEATH_DIED ) {
5115 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5116 event_music_player_death();
5118 // multiplayer clients set their extra check here
5119 if(Game_mode & GM_MULTIPLAYER){
5120 // set the multi died absolute last chance check
5121 Player_multi_died_check = time(NULL);
5124 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5128 case GS_EVENT_NEW_CAMPAIGN:
5129 if (!mission_load_up_campaign()){
5130 readyroom_continue_campaign();
5133 Player_multi_died_check = -1;
5136 case GS_EVENT_CAMPAIGN_CHEAT:
5137 if (!mission_load_up_campaign()){
5139 // bash campaign value
5140 extern char Main_hall_campaign_cheat[512];
5143 // look for the mission
5144 for(idx=0; idx<Campaign.num_missions; idx++){
5145 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5146 Campaign.next_mission = idx;
5147 Campaign.prev_mission = idx - 1;
5154 readyroom_continue_campaign();
5157 Player_multi_died_check = -1;
5160 case GS_EVENT_CAMPAIGN_ROOM:
5161 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5164 case GS_EVENT_CMD_BRIEF:
5165 gameseq_set_state(GS_STATE_CMD_BRIEF);
5168 case GS_EVENT_RED_ALERT:
5169 gameseq_set_state(GS_STATE_RED_ALERT);
5172 case GS_EVENT_CREDITS:
5173 gameseq_set_state( GS_STATE_CREDITS );
5176 case GS_EVENT_VIEW_MEDALS:
5177 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5180 case GS_EVENT_SHOW_GOALS:
5181 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5184 case GS_EVENT_HOTKEY_SCREEN:
5185 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5188 // multiplayer stuff follow these comments
5190 case GS_EVENT_MULTI_JOIN_GAME:
5191 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5194 case GS_EVENT_MULTI_HOST_SETUP:
5195 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5198 case GS_EVENT_MULTI_CLIENT_SETUP:
5199 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5202 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5203 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5206 case GS_EVENT_MULTI_STD_WAIT:
5207 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5210 case GS_EVENT_STANDALONE_MAIN:
5211 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5214 case GS_EVENT_MULTI_PAUSE:
5215 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5218 case GS_EVENT_INGAME_PRE_JOIN:
5219 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5222 case GS_EVENT_EVENT_DEBUG:
5223 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5226 // Start a warpout where player automatically goes 70 no matter what
5227 // and can't cancel out of it.
5228 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5229 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5231 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5232 Player->saved_viewer_mode = Viewer_mode;
5233 Player->control_mode = PCM_WARPOUT_STAGE1;
5234 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5235 Warpout_time = 0.0f; // Start timer!
5238 case GS_EVENT_PLAYER_WARPOUT_START:
5239 if ( Player->control_mode != PCM_NORMAL ) {
5240 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5242 Player->saved_viewer_mode = Viewer_mode;
5243 Player->control_mode = PCM_WARPOUT_STAGE1;
5244 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5245 Warpout_time = 0.0f; // Start timer!
5246 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5250 case GS_EVENT_PLAYER_WARPOUT_STOP:
5251 if ( Player->control_mode != PCM_NORMAL ) {
5252 if ( !Warpout_forced ) { // cannot cancel forced warpout
5253 Player->control_mode = PCM_NORMAL;
5254 Viewer_mode = Player->saved_viewer_mode;
5255 hud_subspace_notify_abort();
5256 mprintf(( "Player put back to normal mode.\n" ));
5257 if ( Warpout_sound > -1 ) {
5258 snd_stop( Warpout_sound );
5265 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5266 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5267 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5268 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5270 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5271 shipfx_warpout_start( Player_obj );
5272 Player->control_mode = PCM_WARPOUT_STAGE2;
5273 Player->saved_viewer_mode = Viewer_mode;
5274 Viewer_mode |= VM_WARP_CHASE;
5276 vector tmp = Player_obj->pos;
5278 ship_get_eye( &tmp, &tmp_m, Player_obj );
5279 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5280 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5281 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5283 camera_set_position( &tmp );
5284 camera_set_orient( &Player_obj->orient );
5285 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5287 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5288 camera_set_velocity( &tmp_vel, 1);
5292 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5293 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5294 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5295 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5297 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5298 Player->control_mode = PCM_WARPOUT_STAGE3;
5302 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5303 mprintf(( "Player warped out. Going to debriefing!\n" ));
5304 Player->control_mode = PCM_NORMAL;
5305 Viewer_mode = Player->saved_viewer_mode;
5308 // we have a special debriefing screen for multiplayer furballs
5309 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5310 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5312 // do the normal debriefing for all other situations
5314 gameseq_post_event(GS_EVENT_DEBRIEF);
5318 case GS_EVENT_STANDALONE_POSTGAME:
5319 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5322 case GS_EVENT_INITIAL_PLAYER_SELECT:
5323 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5326 case GS_EVENT_GAME_INIT:
5327 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5328 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5330 // see if the command line option has been set to use the last pilot, and act acoordingly
5331 if( player_select_get_last_pilot() ) {
5332 // always enter the main menu -- do the automatic network startup stuff elsewhere
5333 // so that we still have valid checks for networking modes, etc.
5334 gameseq_set_state(GS_STATE_MAIN_MENU);
5336 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5341 case GS_EVENT_MULTI_MISSION_SYNC:
5342 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5345 case GS_EVENT_MULTI_START_GAME:
5346 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5349 case GS_EVENT_MULTI_HOST_OPTIONS:
5350 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5353 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5354 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5357 case GS_EVENT_TEAM_SELECT:
5358 gameseq_set_state(GS_STATE_TEAM_SELECT);
5361 case GS_EVENT_END_CAMPAIGN:
5362 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5365 case GS_EVENT_END_DEMO:
5366 gameseq_set_state(GS_STATE_END_DEMO);
5369 case GS_EVENT_LOOP_BRIEF:
5370 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5379 // Called when a state is being left.
5380 // The current state is still at old_state, but as soon as
5381 // this function leaves, then the current state will become
5382 // new state. You should never try to change the state
5383 // in here... if you think you need to, you probably really
5384 // need to post an event, not change the state.
5385 void game_leave_state( int old_state, int new_state )
5387 int end_mission = 1;
5389 switch (new_state) {
5390 case GS_STATE_GAME_PAUSED:
5391 case GS_STATE_DEBUG_PAUSED:
5392 case GS_STATE_OPTIONS_MENU:
5393 case GS_STATE_CONTROL_CONFIG:
5394 case GS_STATE_MISSION_LOG_SCROLLBACK:
5395 case GS_STATE_DEATH_DIED:
5396 case GS_STATE_SHOW_GOALS:
5397 case GS_STATE_HOTKEY_SCREEN:
5398 case GS_STATE_MULTI_PAUSED:
5399 case GS_STATE_TRAINING_PAUSED:
5400 case GS_STATE_EVENT_DEBUG:
5401 case GS_STATE_GAMEPLAY_HELP:
5402 end_mission = 0; // these events shouldn't end a mission
5406 switch (old_state) {
5407 case GS_STATE_BRIEFING:
5408 brief_stop_voices();
5409 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5410 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5411 && (new_state != GS_STATE_TEAM_SELECT) ){
5412 common_select_close();
5413 if ( new_state == GS_STATE_MAIN_MENU ) {
5414 freespace_stop_mission();
5418 // COMMAND LINE OPTION
5419 if (Cmdline_multi_stream_chat_to_file){
5420 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5421 cfclose(Multi_chat_stream);
5425 case GS_STATE_DEBRIEF:
5426 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5431 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5432 multi_df_debrief_close();
5435 case GS_STATE_LOAD_MISSION_MENU:
5436 mission_load_menu_close();
5439 case GS_STATE_SIMULATOR_ROOM:
5443 case GS_STATE_CAMPAIGN_ROOM:
5444 campaign_room_close();
5447 case GS_STATE_CMD_BRIEF:
5448 if (new_state == GS_STATE_OPTIONS_MENU) {
5453 if (new_state == GS_STATE_MAIN_MENU)
5454 freespace_stop_mission();
5459 case GS_STATE_RED_ALERT:
5463 case GS_STATE_SHIP_SELECT:
5464 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5465 new_state != GS_STATE_HOTKEY_SCREEN &&
5466 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5467 common_select_close();
5468 if ( new_state == GS_STATE_MAIN_MENU ) {
5469 freespace_stop_mission();
5474 case GS_STATE_WEAPON_SELECT:
5475 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5476 new_state != GS_STATE_HOTKEY_SCREEN &&
5477 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5478 common_select_close();
5479 if ( new_state == GS_STATE_MAIN_MENU ) {
5480 freespace_stop_mission();
5485 case GS_STATE_TEAM_SELECT:
5486 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5487 new_state != GS_STATE_HOTKEY_SCREEN &&
5488 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5489 common_select_close();
5490 if ( new_state == GS_STATE_MAIN_MENU ) {
5491 freespace_stop_mission();
5496 case GS_STATE_MAIN_MENU:
5497 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5504 case GS_STATE_OPTIONS_MENU:
5505 //game_start_time();
5506 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5507 multi_join_clear_game_list();
5509 options_menu_close();
5512 case GS_STATE_BARRACKS_MENU:
5513 if(new_state != GS_STATE_VIEW_MEDALS){
5518 case GS_STATE_MISSION_LOG_SCROLLBACK:
5519 hud_scrollback_close();
5522 case GS_STATE_TRAINING_MENU:
5523 training_menu_close();
5526 case GS_STATE_GAME_PLAY:
5527 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5528 player_save_target_and_weapon_link_prefs();
5529 game_stop_looped_sounds();
5532 sound_env_disable();
5533 joy_ff_stop_effects();
5535 // stop game time under certain conditions
5536 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5541 // shut down any recording or playing demos
5546 // when in multiplayer and going back to the main menu, send a leave game packet
5547 // right away (before calling stop mission). stop_mission was taking to long to
5548 // close mission down and I want people to get notified ASAP.
5549 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5550 multi_quit_game(PROMPT_NONE);
5553 freespace_stop_mission();
5554 Game_time_compression = F1_0;
5558 case GS_STATE_TECH_MENU:
5562 case GS_STATE_TRAINING_PAUSED:
5563 Training_num_lines = 0;
5564 // fall through to GS_STATE_GAME_PAUSED
5566 case GS_STATE_GAME_PAUSED:
5568 if ( end_mission ) {
5573 case GS_STATE_DEBUG_PAUSED:
5576 pause_debug_close();
5580 case GS_STATE_HUD_CONFIG:
5584 // join/start a game
5585 case GS_STATE_MULTI_JOIN_GAME:
5586 if(new_state != GS_STATE_OPTIONS_MENU){
5587 multi_join_game_close();
5591 case GS_STATE_MULTI_HOST_SETUP:
5592 case GS_STATE_MULTI_CLIENT_SETUP:
5593 // if this is just the host going into the options screen, don't do anything
5594 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5598 // close down the proper state
5599 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5600 multi_create_game_close();
5602 multi_game_client_setup_close();
5605 // COMMAND LINE OPTION
5606 if (Cmdline_multi_stream_chat_to_file){
5607 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5608 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5609 cfclose(Multi_chat_stream);
5614 case GS_STATE_CONTROL_CONFIG:
5615 control_config_close();
5618 case GS_STATE_DEATH_DIED:
5619 Game_mode &= ~GM_DEAD_DIED;
5621 // early end while respawning or blowing up in a multiplayer game
5622 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5624 freespace_stop_mission();
5628 case GS_STATE_DEATH_BLEW_UP:
5629 Game_mode &= ~GM_DEAD_BLEW_UP;
5631 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5632 // to determine if I should do anything.
5633 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5635 freespace_stop_mission();
5638 // if we are not respawing as an observer or as a player, our new state will not
5639 // be gameplay state.
5640 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5641 game_stop_time(); // hasn't been called yet!!
5642 freespace_stop_mission();
5648 case GS_STATE_CREDITS:
5652 case GS_STATE_VIEW_MEDALS:
5656 case GS_STATE_SHOW_GOALS:
5657 mission_show_goals_close();
5660 case GS_STATE_HOTKEY_SCREEN:
5661 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5662 mission_hotkey_close();
5666 case GS_STATE_MULTI_MISSION_SYNC:
5667 // if we're moving into the options menu, don't do anything
5668 if(new_state == GS_STATE_OPTIONS_MENU){
5672 Assert( Game_mode & GM_MULTIPLAYER );
5674 if ( new_state == GS_STATE_GAME_PLAY ){
5675 // palette_restore_palette();
5677 // change a couple of flags to indicate our state!!!
5678 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5679 send_netplayer_update_packet();
5681 // set the game mode
5682 Game_mode |= GM_IN_MISSION;
5686 case GS_STATE_VIEW_CUTSCENES:
5687 cutscenes_screen_close();
5690 case GS_STATE_MULTI_STD_WAIT:
5691 multi_standalone_wait_close();
5694 case GS_STATE_STANDALONE_MAIN:
5695 standalone_main_close();
5696 if(new_state == GS_STATE_MULTI_STD_WAIT){
5697 init_multiplayer_stats();
5701 case GS_STATE_MULTI_PAUSED:
5702 // if ( end_mission ){
5707 case GS_STATE_INGAME_PRE_JOIN:
5708 multi_ingame_select_close();
5711 case GS_STATE_STANDALONE_POSTGAME:
5712 multi_standalone_postgame_close();
5715 case GS_STATE_INITIAL_PLAYER_SELECT:
5716 player_select_close();
5719 case GS_STATE_MULTI_START_GAME:
5720 multi_start_game_close();
5723 case GS_STATE_MULTI_HOST_OPTIONS:
5724 multi_host_options_close();
5727 case GS_STATE_END_OF_CAMPAIGN:
5728 mission_campaign_end_close();
5731 case GS_STATE_LOOP_BRIEF:
5737 // Called when a state is being entered.
5738 // The current state is set to the state we're entering at
5739 // this point, and old_state is set to the state we're coming
5740 // from. You should never try to change the state
5741 // in here... if you think you need to, you probably really
5742 // need to post an event, not change the state.
5744 void game_enter_state( int old_state, int new_state )
5746 switch (new_state) {
5747 case GS_STATE_MAIN_MENU:
5748 // in multiplayer mode, be sure that we are not doing networking anymore.
5749 if ( Game_mode & GM_MULTIPLAYER ) {
5750 Assert( Net_player != NULL );
5751 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5754 Game_time_compression = F1_0;
5756 // determine which ship this guy is currently based on
5757 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5760 if (Player->on_bastion) {
5768 case GS_STATE_BRIEFING:
5769 main_hall_stop_music();
5770 main_hall_stop_ambient();
5772 if (Game_mode & GM_NORMAL) {
5773 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5774 // MWA: or from options or hotkey screens
5775 // JH: or if the command brief state already did this
5776 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5777 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5778 && (old_state != GS_STATE_CMD_BRIEF) ) {
5779 if ( !game_start_mission() ) // this should put us into a new state on failure!
5783 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5784 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5785 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5787 Game_time_compression = F1_0;
5789 if ( red_alert_mission() ) {
5790 gameseq_post_event(GS_EVENT_RED_ALERT);
5797 case GS_STATE_DEBRIEF:
5798 game_stop_looped_sounds();
5799 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5800 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5805 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5806 multi_df_debrief_init();
5809 case GS_STATE_LOAD_MISSION_MENU:
5810 mission_load_menu_init();
5813 case GS_STATE_SIMULATOR_ROOM:
5817 case GS_STATE_CAMPAIGN_ROOM:
5818 campaign_room_init();
5821 case GS_STATE_RED_ALERT:
5822 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5826 case GS_STATE_CMD_BRIEF: {
5827 int team_num = 0; // team number used as index for which cmd brief to use.
5829 if (old_state == GS_STATE_OPTIONS_MENU) {
5833 main_hall_stop_music();
5834 main_hall_stop_ambient();
5836 if (Game_mode & GM_NORMAL) {
5837 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5838 // MWA: or from options or hotkey screens
5839 // JH: or if the command brief state already did this
5840 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5841 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5842 if ( !game_start_mission() ) // this should put us into a new state on failure!
5847 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5848 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5849 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5851 cmd_brief_init(team_num);
5857 case GS_STATE_SHIP_SELECT:
5861 case GS_STATE_WEAPON_SELECT:
5862 weapon_select_init();
5865 case GS_STATE_TEAM_SELECT:
5869 case GS_STATE_GAME_PAUSED:
5874 case GS_STATE_DEBUG_PAUSED:
5875 // game_stop_time();
5876 // os_set_title("FreeSpace - PAUSED");
5879 case GS_STATE_TRAINING_PAUSED:
5886 case GS_STATE_OPTIONS_MENU:
5888 options_menu_init();
5891 case GS_STATE_GAME_PLAY:
5892 // coming from the gameplay state or the main menu, we might need to load the mission
5893 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5894 if ( !game_start_mission() ) // this should put us into a new state.
5899 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5900 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5901 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5902 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5903 (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) ) {
5904 // JAS: Used to do all paging here.
5908 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5912 main_hall_stop_music();
5913 main_hall_stop_ambient();
5914 event_music_first_pattern(); // start the first pattern
5917 // special code that restores player ship selection and weapons loadout when doing a quick start
5918 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5919 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5920 wss_direct_restore_loadout();
5924 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5925 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5926 event_music_first_pattern(); // start the first pattern
5929 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5930 event_music_first_pattern(); // start the first pattern
5932 player_restore_target_and_weapon_link_prefs();
5934 Game_mode |= GM_IN_MISSION;
5937 // required to truely make mouse deltas zeroed in debug mouse code
5938 void mouse_force_pos(int x, int y);
5939 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5944 // only start time if in single player, or coming from multi wait state
5947 (Game_mode & GM_NORMAL) &&
5948 (old_state != GS_STATE_VIEW_CUTSCENES)
5950 (Game_mode & GM_MULTIPLAYER) && (
5951 (old_state == GS_STATE_MULTI_PAUSED) ||
5952 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5958 // when coming from the multi paused state, reset the timestamps
5959 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5960 multi_reset_timestamps();
5963 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5964 // initialize all object update details
5965 multi_oo_gameplay_init();
5968 // under certain circumstances, the server should reset the object update rate limiting stuff
5969 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5970 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5972 // reinitialize the rate limiting system for all clients
5973 multi_oo_rate_init_all();
5976 // multiplayer clients should always re-initialize their control info rate limiting system
5977 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5978 multi_oo_rate_init_all();
5982 if(Game_mode & GM_MULTIPLAYER){
5983 multi_ping_reset_players();
5986 Game_subspace_effect = 0;
5987 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5988 Game_subspace_effect = 1;
5989 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5990 game_start_subspace_ambient_sound();
5994 sound_env_set(&Game_sound_env);
5995 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5997 // clear multiplayer button info i
5998 extern button_info Multi_ship_status_bi;
5999 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6002 case GS_STATE_HUD_CONFIG:
6006 case GS_STATE_MULTI_JOIN_GAME:
6007 multi_join_clear_game_list();
6009 if (old_state != GS_STATE_OPTIONS_MENU) {
6010 multi_join_game_init();
6015 case GS_STATE_MULTI_HOST_SETUP:
6016 // don't reinitialize if we're coming back from the host options screen
6017 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6018 multi_create_game_init();
6023 case GS_STATE_MULTI_CLIENT_SETUP:
6024 if (old_state != GS_STATE_OPTIONS_MENU) {
6025 multi_game_client_setup_init();
6030 case GS_STATE_CONTROL_CONFIG:
6031 control_config_init();
6034 case GS_STATE_TECH_MENU:
6038 case GS_STATE_BARRACKS_MENU:
6039 if(old_state != GS_STATE_VIEW_MEDALS){
6044 case GS_STATE_MISSION_LOG_SCROLLBACK:
6045 hud_scrollback_init();
6048 case GS_STATE_DEATH_DIED:
6049 Player_died_time = timestamp(10);
6051 if(!(Game_mode & GM_MULTIPLAYER)){
6052 player_show_death_message();
6054 Game_mode |= GM_DEAD_DIED;
6057 case GS_STATE_DEATH_BLEW_UP:
6058 if ( !popupdead_is_active() ) {
6059 Player_ai->target_objnum = -1;
6062 // stop any local EMP effect
6065 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6066 Game_mode |= GM_DEAD_BLEW_UP;
6067 Show_viewing_from_self = 0;
6069 // timestamp how long we should wait before displaying the died popup
6070 if ( !popupdead_is_active() ) {
6071 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6075 case GS_STATE_GAMEPLAY_HELP:
6076 gameplay_help_init();
6079 case GS_STATE_CREDITS:
6080 main_hall_stop_music();
6081 main_hall_stop_ambient();
6085 case GS_STATE_VIEW_MEDALS:
6086 medal_main_init(Player);
6089 case GS_STATE_SHOW_GOALS:
6090 mission_show_goals_init();
6093 case GS_STATE_HOTKEY_SCREEN:
6094 mission_hotkey_init();
6097 case GS_STATE_MULTI_MISSION_SYNC:
6098 // if we're coming from the options screen, don't do any
6099 if(old_state == GS_STATE_OPTIONS_MENU){
6103 switch(Multi_sync_mode){
6104 case MULTI_SYNC_PRE_BRIEFING:
6105 // if moving from game forming to the team select state
6108 case MULTI_SYNC_POST_BRIEFING:
6109 // if moving from briefing into the mission itself
6112 // tell everyone that we're now loading data
6113 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6114 send_netplayer_update_packet();
6116 // JAS: Used to do all paging here!!!!
6118 Net_player->state = NETPLAYER_STATE_WAITING;
6119 send_netplayer_update_packet();
6121 Game_time_compression = F1_0;
6123 case MULTI_SYNC_INGAME:
6129 case GS_STATE_VIEW_CUTSCENES:
6130 cutscenes_screen_init();
6133 case GS_STATE_MULTI_STD_WAIT:
6134 multi_standalone_wait_init();
6137 case GS_STATE_STANDALONE_MAIN:
6138 // don't initialize if we're coming from one of these 2 states unless there are no
6139 // players left (reset situation)
6140 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6141 standalone_main_init();
6145 case GS_STATE_MULTI_PAUSED:
6149 case GS_STATE_INGAME_PRE_JOIN:
6150 multi_ingame_select_init();
6153 case GS_STATE_STANDALONE_POSTGAME:
6154 multi_standalone_postgame_init();
6157 case GS_STATE_INITIAL_PLAYER_SELECT:
6158 player_select_init();
6161 case GS_STATE_MULTI_START_GAME:
6162 multi_start_game_init();
6165 case GS_STATE_MULTI_HOST_OPTIONS:
6166 multi_host_options_init();
6169 case GS_STATE_END_OF_CAMPAIGN:
6170 mission_campaign_end_init();
6173 case GS_STATE_LOOP_BRIEF:
6180 // do stuff that may need to be done regardless of state
6181 void game_do_state_common(int state,int no_networking)
6183 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6184 snd_do_frame(); // update sound system
6185 event_music_do_frame(); // music needs to play across many states
6187 multi_log_process();
6189 if (no_networking) {
6193 // maybe do a multiplayer frame based on game mode and state type
6194 if (Game_mode & GM_MULTIPLAYER) {
6196 case GS_STATE_OPTIONS_MENU:
6197 case GS_STATE_GAMEPLAY_HELP:
6198 case GS_STATE_HOTKEY_SCREEN:
6199 case GS_STATE_HUD_CONFIG:
6200 case GS_STATE_CONTROL_CONFIG:
6201 case GS_STATE_MISSION_LOG_SCROLLBACK:
6202 case GS_STATE_SHOW_GOALS:
6203 case GS_STATE_VIEW_CUTSCENES:
6204 case GS_STATE_EVENT_DEBUG:
6205 multi_maybe_do_frame();
6209 game_do_networking();
6213 // Called once a frame.
6214 // You should never try to change the state
6215 // in here... if you think you need to, you probably really
6216 // need to post an event, not change the state.
6217 int Game_do_state_should_skip = 0;
6218 void game_do_state(int state)
6220 // always lets the do_state_common() function determine if the state should be skipped
6221 Game_do_state_should_skip = 0;
6223 // legal to set the should skip state anywhere in this function
6224 game_do_state_common(state); // do stuff that may need to be done regardless of state
6226 if(Game_do_state_should_skip){
6231 case GS_STATE_MAIN_MENU:
6232 game_set_frametime(GS_STATE_MAIN_MENU);
6233 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6236 main_hall_do(flFrametime);
6240 case GS_STATE_OPTIONS_MENU:
6241 game_set_frametime(GS_STATE_OPTIONS_MENU);
6242 options_menu_do_frame(flFrametime);
6245 case GS_STATE_BARRACKS_MENU:
6246 game_set_frametime(GS_STATE_BARRACKS_MENU);
6247 barracks_do_frame(flFrametime);
6250 case GS_STATE_TRAINING_MENU:
6251 game_set_frametime(GS_STATE_TRAINING_MENU);
6252 training_menu_do_frame(flFrametime);
6255 case GS_STATE_TECH_MENU:
6256 game_set_frametime(GS_STATE_TECH_MENU);
6257 techroom_do_frame(flFrametime);
6260 case GS_STATE_GAMEPLAY_HELP:
6261 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6262 gameplay_help_do_frame(flFrametime);
6265 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6269 case GS_STATE_GAME_PAUSED:
6273 case GS_STATE_DEBUG_PAUSED:
6275 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6280 case GS_STATE_TRAINING_PAUSED:
6281 game_training_pause_do();
6284 case GS_STATE_LOAD_MISSION_MENU:
6285 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6286 mission_load_menu_do();
6289 case GS_STATE_BRIEFING:
6290 game_set_frametime(GS_STATE_BRIEFING);
6291 brief_do_frame(flFrametime);
6294 case GS_STATE_DEBRIEF:
6295 game_set_frametime(GS_STATE_DEBRIEF);
6296 debrief_do_frame(flFrametime);
6299 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6300 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6301 multi_df_debrief_do();
6304 case GS_STATE_SHIP_SELECT:
6305 game_set_frametime(GS_STATE_SHIP_SELECT);
6306 ship_select_do(flFrametime);
6309 case GS_STATE_WEAPON_SELECT:
6310 game_set_frametime(GS_STATE_WEAPON_SELECT);
6311 weapon_select_do(flFrametime);
6314 case GS_STATE_MISSION_LOG_SCROLLBACK:
6315 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6316 hud_scrollback_do_frame(flFrametime);
6319 case GS_STATE_HUD_CONFIG:
6320 game_set_frametime(GS_STATE_HUD_CONFIG);
6321 hud_config_do_frame(flFrametime);
6324 case GS_STATE_MULTI_JOIN_GAME:
6325 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6326 multi_join_game_do_frame();
6329 case GS_STATE_MULTI_HOST_SETUP:
6330 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6331 multi_create_game_do();
6334 case GS_STATE_MULTI_CLIENT_SETUP:
6335 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6336 multi_game_client_setup_do_frame();
6339 case GS_STATE_CONTROL_CONFIG:
6340 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6341 control_config_do_frame(flFrametime);
6344 case GS_STATE_DEATH_DIED:
6348 case GS_STATE_DEATH_BLEW_UP:
6352 case GS_STATE_SIMULATOR_ROOM:
6353 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6354 sim_room_do_frame(flFrametime);
6357 case GS_STATE_CAMPAIGN_ROOM:
6358 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6359 campaign_room_do_frame(flFrametime);
6362 case GS_STATE_RED_ALERT:
6363 game_set_frametime(GS_STATE_RED_ALERT);
6364 red_alert_do_frame(flFrametime);
6367 case GS_STATE_CMD_BRIEF:
6368 game_set_frametime(GS_STATE_CMD_BRIEF);
6369 cmd_brief_do_frame(flFrametime);
6372 case GS_STATE_CREDITS:
6373 game_set_frametime(GS_STATE_CREDITS);
6374 credits_do_frame(flFrametime);
6377 case GS_STATE_VIEW_MEDALS:
6378 game_set_frametime(GS_STATE_VIEW_MEDALS);
6382 case GS_STATE_SHOW_GOALS:
6383 game_set_frametime(GS_STATE_SHOW_GOALS);
6384 mission_show_goals_do_frame(flFrametime);
6387 case GS_STATE_HOTKEY_SCREEN:
6388 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6389 mission_hotkey_do_frame(flFrametime);
6392 case GS_STATE_VIEW_CUTSCENES:
6393 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6394 cutscenes_screen_do_frame();
6397 case GS_STATE_MULTI_STD_WAIT:
6398 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6399 multi_standalone_wait_do();
6402 case GS_STATE_STANDALONE_MAIN:
6403 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6404 standalone_main_do();
6407 case GS_STATE_MULTI_PAUSED:
6408 game_set_frametime(GS_STATE_MULTI_PAUSED);
6412 case GS_STATE_TEAM_SELECT:
6413 game_set_frametime(GS_STATE_TEAM_SELECT);
6417 case GS_STATE_INGAME_PRE_JOIN:
6418 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6419 multi_ingame_select_do();
6422 case GS_STATE_EVENT_DEBUG:
6424 game_set_frametime(GS_STATE_EVENT_DEBUG);
6425 game_show_event_debug(flFrametime);
6429 case GS_STATE_STANDALONE_POSTGAME:
6430 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6431 multi_standalone_postgame_do();
6434 case GS_STATE_INITIAL_PLAYER_SELECT:
6435 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6439 case GS_STATE_MULTI_MISSION_SYNC:
6440 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6444 case GS_STATE_MULTI_START_GAME:
6445 game_set_frametime(GS_STATE_MULTI_START_GAME);
6446 multi_start_game_do();
6449 case GS_STATE_MULTI_HOST_OPTIONS:
6450 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6451 multi_host_options_do();
6454 case GS_STATE_END_OF_CAMPAIGN:
6455 mission_campaign_end_do();
6458 case GS_STATE_END_DEMO:
6459 game_set_frametime(GS_STATE_END_DEMO);
6460 end_demo_campaign_do();
6463 case GS_STATE_LOOP_BRIEF:
6464 game_set_frametime(GS_STATE_LOOP_BRIEF);
6468 } // end switch(gs_current_state)
6472 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6473 int game_do_ram_check(int ram_in_bytes)
6475 if ( ram_in_bytes < 30*1024*1024 ) {
6476 int allowed_to_run = 1;
6477 if ( ram_in_bytes < 25*1024*1024 ) {
6482 int Freespace_total_ram_MB;
6483 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6485 if ( allowed_to_run ) {
6487 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);
6491 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6492 if ( msgbox_rval == IDCANCEL ) {
6499 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);
6501 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6512 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6513 // If so, copy it over and remove the update directory.
6514 void game_maybe_update_launcher(char *exe_dir)
6517 char src_filename[MAX_PATH];
6518 char dest_filename[MAX_PATH];
6520 strcpy(src_filename, exe_dir);
6521 strcat(src_filename, NOX("\\update\\freespace.exe"));
6523 strcpy(dest_filename, exe_dir);
6524 strcat(dest_filename, NOX("\\freespace.exe"));
6526 // see if src_filename exists
6528 fp = fopen(src_filename, "rb");
6534 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6536 // copy updated freespace.exe to freespace exe dir
6537 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6538 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 );
6542 // delete the file in the update directory
6543 DeleteFile(src_filename);
6545 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6546 char update_dir[MAX_PATH];
6547 strcpy(update_dir, exe_dir);
6548 strcat(update_dir, NOX("\\update"));
6549 RemoveDirectory(update_dir);
6555 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6559 int sub_total_destroyed = 0;
6563 // get the total for all his children
6564 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6565 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6568 // find the # of faces for this _individual_ object
6569 total = submodel_get_num_polys(model_num, sm);
6570 if(strstr(pm->submodel[sm].name, "-destroyed")){
6571 sub_total_destroyed = total;
6575 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6578 *out_total += total + sub_total;
6579 *out_destroyed_total += sub_total_destroyed;
6582 #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);
6583 void game_spew_pof_info()
6585 char *pof_list[1000];
6588 int idx, model_num, i, j;
6590 int total, root_total, model_total, destroyed_total, counted;
6594 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6596 // spew info on all the pofs
6602 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6607 for(idx=0; idx<num_files; idx++, counted++){
6608 sprintf(str, "%s.pof", pof_list[idx]);
6609 model_num = model_load(str, 0, NULL);
6611 pm = model_get(model_num);
6613 // if we have a real model
6618 // go through and print all raw submodels
6619 cfputs("RAW\n", out);
6622 for (i=0; i<pm->n_models; i++) {
6623 total = submodel_get_num_polys(model_num, i);
6625 model_total += total;
6626 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6629 sprintf(str, "Model total %d\n", model_total);
6632 // now go through and do it by LOD
6633 cfputs("BY LOD\n\n", out);
6634 for(i=0; i<pm->n_detail_levels; i++){
6635 sprintf(str, "LOD %d\n", i);
6639 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6641 destroyed_total = 0;
6642 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6643 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6646 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6649 sprintf(str, "TOTAL: %d\n", total + root_total);
6651 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6653 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6656 cfputs("------------------------------------------------------------------------\n\n", out);
6660 if(counted >= MAX_POLYGON_MODELS - 5){
6673 game_spew_pof_info();
6676 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6681 // Don't let more than one instance of Freespace run.
6682 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6684 SetForegroundWindow(hwnd);
6689 // Find out how much RAM is on this machine
6692 ms.dwLength = sizeof(MEMORYSTATUS);
6693 GlobalMemoryStatus(&ms);
6694 Freespace_total_ram = ms.dwTotalPhys;
6696 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6700 if ( ms.dwTotalVirtual < 1024 ) {
6701 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6705 if (!vm_init(24*1024*1024)) {
6706 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 );
6710 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6712 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);
6722 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6723 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6724 seem worth bothering with.
6728 lResult = RegOpenKeyEx(
6729 HKEY_LOCAL_MACHINE, // Where it is
6730 "Software\\Microsoft\\DirectX", // name of key
6731 NULL, // DWORD reserved
6732 KEY_QUERY_VALUE, // Allows all changes
6733 &hKey // Location to store key
6736 if (lResult == ERROR_SUCCESS) {
6738 DWORD dwType, dwLen;
6741 lResult = RegQueryValueEx(
6742 hKey, // Handle to key
6743 "Version", // The values name
6744 NULL, // DWORD reserved
6745 &dwType, // What kind it is
6746 (ubyte *) version, // value to set
6747 &dwLen // How many bytes to set
6750 if (lResult == ERROR_SUCCESS) {
6751 dx_version = atoi(strstr(version, ".") + 1);
6755 DWORD dwType, dwLen;
6758 lResult = RegQueryValueEx(
6759 hKey, // Handle to key
6760 "InstalledVersion", // The values name
6761 NULL, // DWORD reserved
6762 &dwType, // What kind it is
6763 (ubyte *) &val, // value to set
6764 &dwLen // How many bytes to set
6767 if (lResult == ERROR_SUCCESS) {
6775 if (dx_version < 3) {
6776 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6777 "latest version of DirectX at:\n\n"
6778 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6780 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6781 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6786 //=====================================================
6787 // Make sure we're running in the right directory.
6791 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6792 char *p = exe_dir + strlen(exe_dir);
6794 // chop off the filename
6795 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6801 if ( strlen(exe_dir) > 0 ) {
6802 SetCurrentDirectory(exe_dir);
6805 // check for updated freespace.exe
6806 game_maybe_update_launcher(exe_dir);
6814 extern void windebug_memwatch_init();
6815 windebug_memwatch_init();
6819 parse_cmdline(szCmdLine);
6821 #ifdef STANDALONE_ONLY_BUILD
6823 nprintf(("Network", "Standalone running"));
6826 nprintf(("Network", "Standalone running"));
6834 // maybe spew pof stuff
6835 if(Cmdline_spew_pof_info){
6836 game_spew_pof_info();
6841 // non-demo, non-standalone, play the intro movie
6846 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) ){
6848 #if defined(OEM_BUILD)
6849 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6851 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6852 #endif // defined(OEM_BUILD)
6857 if ( !Is_standalone ) {
6859 // release -- movies always play
6862 // 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
6864 // movie_play( NOX("intro.mve"), 0 );
6866 // debug version, movie will only play with -showmovies
6867 #elif !defined(NDEBUG)
6870 // movie_play( NOX("intro.mve"), 0);
6873 if ( Cmdline_show_movies )
6874 movie_play( NOX("intro.mve"), 0 );
6883 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6885 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6889 // only important for non THREADED mode
6892 state = gameseq_process_events();
6893 if ( state == GS_STATE_QUIT_GAME ){
6900 demo_upsell_show_screens();
6902 #elif defined(OEM_BUILD)
6903 // show upsell screens on exit
6904 oem_upsell_show_screens();
6911 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6917 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6919 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6921 // Do nothing here - RecordExceptionInfo() has already done
6922 // everything that is needed. Actually this code won't even
6923 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6924 // the __except clause.
6930 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6931 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6937 // launcher the fslauncher program on exit
6938 void game_launch_launcher_on_exit()
6942 PROCESS_INFORMATION pi;
6943 char cmd_line[2048];
6944 char original_path[1024] = "";
6946 memset( &si, 0, sizeof(STARTUPINFO) );
6950 _getcwd(original_path, 1023);
6952 // set up command line
6953 strcpy(cmd_line, original_path);
6954 strcat(cmd_line, "\\");
6955 strcat(cmd_line, LAUNCHER_FNAME);
6956 strcat(cmd_line, " -straight_to_update");
6958 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6959 cmd_line, // pointer to command line string
6960 NULL, // pointer to process security attributes
6961 NULL, // pointer to thread security attributes
6962 FALSE, // handle inheritance flag
6963 CREATE_DEFAULT_ERROR_MODE, // creation flags
6964 NULL, // pointer to new environment block
6965 NULL, // pointer to current directory name
6966 &si, // pointer to STARTUPINFO
6967 &pi // pointer to PROCESS_INFORMATION
6969 // to eliminate build warnings
6979 // This function is called when FreeSpace terminates normally.
6981 void game_shutdown(void)
6987 // don't ever flip a page on the standalone!
6988 if(!(Game_mode & GM_STANDALONE_SERVER)){
6994 // if the player has left the "player select" screen and quit the game without actually choosing
6995 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6996 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7000 // load up common multiplayer icons
7001 multi_unload_common_icons();
7003 shockwave_close(); // release any memory used by shockwave system
7004 fireball_close(); // free fireball system
7005 ship_close(); // free any memory that was allocated for the ships
7006 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7007 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7008 bm_unload_all(); // free bitmaps
7009 mission_campaign_close(); // close out the campaign stuff
7010 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7012 #ifdef MULTI_USE_LAG
7016 // the menu close functions will unload the bitmaps if they were displayed during the game
7017 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7020 training_menu_close();
7023 extern void joy_close();
7026 audiostream_close();
7028 event_music_close();
7032 // HACKITY HACK HACK
7033 // if this flag is set, we should be firing up the launcher when exiting freespace
7034 extern int Multi_update_fireup_launcher_on_exit;
7035 if(Multi_update_fireup_launcher_on_exit){
7036 game_launch_launcher_on_exit();
7040 // game_stop_looped_sounds()
7042 // This function will call the appropriate stop looped sound functions for those
7043 // modules which use looping sounds. It is not enough just to stop a looping sound
7044 // at the DirectSound level, the game is keeping track of looping sounds, and this
7045 // function is used to inform the game that looping sounds are being halted.
7047 void game_stop_looped_sounds()
7049 hud_stop_looped_locking_sounds();
7050 hud_stop_looped_engine_sounds();
7051 afterburner_stop_sounds();
7052 player_stop_looped_sounds();
7053 obj_snd_stop_all(); // stop all object-linked persistant sounds
7054 game_stop_subspace_ambient_sound();
7055 snd_stop(Radar_static_looping);
7056 Radar_static_looping = -1;
7057 snd_stop(Target_static_looping);
7058 shipfx_stop_engine_wash_sound();
7059 Target_static_looping = -1;
7062 //////////////////////////////////////////////////////////////////////////
7064 // Code for supporting an animating mouse pointer
7067 //////////////////////////////////////////////////////////////////////////
7069 typedef struct animating_obj
7078 static animating_obj Animating_mouse;
7080 // ----------------------------------------------------------------------------
7081 // init_animating_pointer()
7083 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7084 // gets properly initialized
7086 void init_animating_pointer()
7088 Animating_mouse.first_frame = -1;
7089 Animating_mouse.num_frames = 0;
7090 Animating_mouse.current_frame = -1;
7091 Animating_mouse.time = 0.0f;
7092 Animating_mouse.elapsed_time = 0.0f;
7095 // ----------------------------------------------------------------------------
7096 // load_animating_pointer()
7098 // Called at game init to load in the frames for the animating mouse pointer
7100 // input: filename => filename of animation file that holds the animation
7102 void load_animating_pointer(char *filename, int dx, int dy)
7107 init_animating_pointer();
7109 am = &Animating_mouse;
7110 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7111 if ( am->first_frame == -1 )
7112 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7113 am->current_frame = 0;
7114 am->time = am->num_frames / i2fl(fps);
7117 // ----------------------------------------------------------------------------
7118 // unload_animating_pointer()
7120 // Called at game shutdown to free the memory used to store the animation frames
7122 void unload_animating_pointer()
7127 am = &Animating_mouse;
7128 for ( i = 0; i < am->num_frames; i++ ) {
7129 Assert( (am->first_frame+i) >= 0 );
7130 bm_release(am->first_frame + i);
7133 am->first_frame = -1;
7135 am->current_frame = -1;
7138 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7139 void game_render_mouse(float frametime)
7144 // if animating cursor exists, play the next frame
7145 am = &Animating_mouse;
7146 if ( am->first_frame != -1 ) {
7147 mouse_get_pos(&mx, &my);
7148 am->elapsed_time += frametime;
7149 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7150 if ( am->current_frame >= am->num_frames ) {
7151 am->current_frame = 0;
7152 am->elapsed_time = 0.0f;
7154 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7158 // ----------------------------------------------------------------------------
7159 // game_maybe_draw_mouse()
7161 // determines whether to draw the mouse pointer at all, and what frame of
7162 // animation to use if the mouse is animating
7164 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7166 // input: frametime => elapsed frame time in seconds since last call
7168 void game_maybe_draw_mouse(float frametime)
7172 game_state = gameseq_get_state();
7174 switch ( game_state ) {
7175 case GS_STATE_GAME_PAUSED:
7176 // case GS_STATE_MULTI_PAUSED:
7177 case GS_STATE_GAME_PLAY:
7178 case GS_STATE_DEATH_DIED:
7179 case GS_STATE_DEATH_BLEW_UP:
7180 if ( popup_active() || popupdead_is_active() ) {
7192 if ( !Mouse_hidden )
7193 game_render_mouse(frametime);
7197 void game_do_training_checks()
7201 waypoint_list *wplp;
7203 if (Training_context & TRAINING_CONTEXT_SPEED) {
7204 s = (int) Player_obj->phys_info.fspeed;
7205 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7206 if (!Training_context_speed_set) {
7207 Training_context_speed_set = 1;
7208 Training_context_speed_timestamp = timestamp();
7212 Training_context_speed_set = 0;
7215 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7216 wplp = &Waypoint_lists[Training_context_path];
7217 if (wplp->count > Training_context_goal_waypoint) {
7218 i = Training_context_goal_waypoint;
7220 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7221 if (d <= Training_context_distance) {
7222 Training_context_at_waypoint = i;
7223 if (Training_context_goal_waypoint == i) {
7224 Training_context_goal_waypoint++;
7225 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7232 if (i == wplp->count)
7235 } while (i != Training_context_goal_waypoint);
7239 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7240 Players_target = Player_ai->target_objnum;
7241 Players_targeted_subsys = Player_ai->targeted_subsys;
7242 Players_target_timestamp = timestamp();
7246 /////////// Following is for event debug view screen
7250 #define EVENT_DEBUG_MAX 5000
7251 #define EVENT_DEBUG_EVENT 0x8000
7253 int Event_debug_index[EVENT_DEBUG_MAX];
7256 void game_add_event_debug_index(int n, int indent)
7258 if (ED_count < EVENT_DEBUG_MAX)
7259 Event_debug_index[ED_count++] = n | (indent << 16);
7262 void game_add_event_debug_sexp(int n, int indent)
7267 if (Sexp_nodes[n].first >= 0) {
7268 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7269 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7273 game_add_event_debug_index(n, indent);
7274 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7275 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7277 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7280 void game_event_debug_init()
7285 for (e=0; e<Num_mission_events; e++) {
7286 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7287 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7291 void game_show_event_debug(float frametime)
7295 int font_height, font_width;
7297 static int scroll_offset = 0;
7299 k = game_check_key();
7305 if (scroll_offset < 0)
7315 scroll_offset -= 20;
7316 if (scroll_offset < 0)
7321 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7325 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7331 gr_set_color_fast(&Color_bright);
7333 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7335 gr_set_color_fast(&Color_normal);
7337 gr_get_string_size(&font_width, &font_height, NOX("test"));
7338 y_max = gr_screen.max_h - font_height - 5;
7342 while (k < ED_count) {
7343 if (y_index > y_max)
7346 z = Event_debug_index[k];
7347 if (z & EVENT_DEBUG_EVENT) {
7349 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7350 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7351 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7352 Mission_events[z].repeat_count, Mission_events[z].interval);
7360 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7361 switch (Sexp_nodes[z & 0x7fff].value) {
7363 strcat(buf, NOX(" (True)"));
7367 strcat(buf, NOX(" (False)"));
7370 case SEXP_KNOWN_TRUE:
7371 strcat(buf, NOX(" (Always true)"));
7374 case SEXP_KNOWN_FALSE:
7375 strcat(buf, NOX(" (Always false)"));
7378 case SEXP_CANT_EVAL:
7379 strcat(buf, NOX(" (Can't eval)"));
7383 case SEXP_NAN_FOREVER:
7384 strcat(buf, NOX(" (Not a number)"));
7389 gr_printf(10, y_index, buf);
7390 y_index += font_height;
7403 extern int Tmap_npixels;
7405 int Tmap_num_too_big = 0;
7406 int Num_models_needing_splitting = 0;
7408 void Time_model( int modelnum )
7410 // mprintf(( "Timing ship '%s'\n", si->name ));
7412 vector eye_pos, model_pos;
7413 matrix eye_orient, model_orient;
7415 polymodel *pm = model_get( modelnum );
7417 int l = strlen(pm->filename);
7419 if ( (l == '/') || (l=='\\') || (l==':')) {
7425 char *pof_file = &pm->filename[l];
7427 int model_needs_splitting = 0;
7429 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7431 for (i=0; i<pm->n_textures; i++ ) {
7432 char filename[1024];
7435 int bmp_num = pm->original_textures[i];
7436 if ( bmp_num > -1 ) {
7437 bm_get_palette(pm->original_textures[i], pal, filename );
7439 bm_get_info( pm->original_textures[i],&w, &h );
7442 if ( (w > 512) || (h > 512) ) {
7443 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7445 model_needs_splitting++;
7448 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7452 if ( model_needs_splitting ) {
7453 Num_models_needing_splitting++;
7455 eye_orient = model_orient = vmd_identity_matrix;
7456 eye_pos = model_pos = vmd_zero_vector;
7458 eye_pos.z = -pm->rad*2.0f;
7460 vector eye_to_model;
7462 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7463 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7465 fix t1 = timer_get_fixed_seconds();
7468 ta.p = ta.b = ta.h = 0.0f;
7473 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7475 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7477 modelstats_num_polys = modelstats_num_verts = 0;
7479 while( ta.h < PI2 ) {
7482 vm_angles_2_matrix(&m1, &ta );
7483 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7490 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7492 model_clear_instance( modelnum );
7493 model_set_detail_level(0); // use highest detail level
7494 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7502 int k = key_inkey();
7503 if ( k == KEY_ESC ) {
7508 fix t2 = timer_get_fixed_seconds();
7510 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7511 //bitmaps_used_this_frame /= framecount;
7513 modelstats_num_polys /= framecount;
7514 modelstats_num_verts /= framecount;
7516 Tmap_npixels /=framecount;
7519 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7520 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 );
7521 // 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 );
7527 int Time_models = 0;
7528 DCF_BOOL( time_models, Time_models );
7530 void Do_model_timings_test()
7534 if ( !Time_models ) return;
7536 mprintf(( "Timing models!\n" ));
7540 ubyte model_used[MAX_POLYGON_MODELS];
7541 int model_id[MAX_POLYGON_MODELS];
7542 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7547 for (i=0; i<Num_ship_types; i++ ) {
7548 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7550 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7551 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7554 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7555 if ( !Texture_fp ) return;
7557 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7558 if ( !Time_fp ) return;
7560 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7561 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7563 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7564 if ( model_used[i] ) {
7565 Time_model( model_id[i] );
7569 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7570 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7579 // Call this function when you want to inform the player that a feature is not
7580 // enabled in the DEMO version of FreSpace
7581 void game_feature_not_in_demo_popup()
7583 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7586 // format the specified time (fixed point) into a nice string
7587 void game_format_time(fix m_time,char *time_str)
7590 int hours,minutes,seconds;
7593 mtime = f2fl(m_time);
7595 // get the hours, minutes and seconds
7596 hours = (int)(mtime / 3600.0f);
7598 mtime -= (3600.0f * (float)hours);
7600 seconds = (int)mtime%60;
7601 minutes = (int)mtime/60;
7603 // print the hour if necessary
7605 sprintf(time_str,XSTR( "%d:", 201),hours);
7606 // if there are less than 10 minutes, print a leading 0
7608 strcpy(tmp,NOX("0"));
7609 strcat(time_str,tmp);
7613 // print the minutes
7615 sprintf(tmp,XSTR( "%d:", 201),minutes);
7616 strcat(time_str,tmp);
7618 sprintf(time_str,XSTR( "%d:", 201),minutes);
7621 // print the seconds
7623 strcpy(tmp,NOX("0"));
7624 strcat(time_str,tmp);
7626 sprintf(tmp,"%d",seconds);
7627 strcat(time_str,tmp);
7630 // Stuff version string in *str.
7631 void get_version_string(char *str)
7634 if ( FS_VERSION_BUILD == 0 ) {
7635 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7637 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7640 #if defined (FS2_DEMO)
7642 #elif defined (OEM_BUILD)
7643 strcat(str, " (OEM)");
7649 char myname[_MAX_PATH];
7650 int namelen, major, minor, build, waste;
7651 unsigned int buf_size;
7657 // Find my EXE file name
7658 hMod = GetModuleHandle(NULL);
7659 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7661 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7662 infop = (char *)malloc(version_size);
7663 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7665 // get the product version
7666 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7667 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7669 sprintf(str,"Dv%d.%02d",major, minor);
7671 sprintf(str,"v%d.%02d",major, minor);
7676 void get_version_string_short(char *str)
7678 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7681 // ----------------------------------------------------------------
7683 // OEM UPSELL SCREENS BEGIN
7685 // ----------------------------------------------------------------
7686 #if defined(OEM_BUILD)
7688 #define NUM_OEM_UPSELL_SCREENS 3
7689 #define OEM_UPSELL_SCREEN_DELAY 10000
7691 static int Oem_upsell_bitmaps_loaded = 0;
7692 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7693 static int Oem_upsell_screen_number = 0;
7694 static int Oem_upsell_show_next_bitmap_time;
7697 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7710 static int Oem_normal_cursor = -1;
7711 static int Oem_web_cursor = -1;
7712 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7713 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7715 void oem_upsell_next_screen()
7717 Oem_upsell_screen_number++;
7718 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7719 // extra long delay, mouse shown on last upsell
7720 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7724 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7728 void oem_upsell_load_bitmaps()
7732 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7733 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7737 void oem_upsell_unload_bitmaps()
7741 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7742 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7743 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7748 Oem_upsell_bitmaps_loaded = 0;
7751 // clickable hotspot on 3rd OEM upsell screen
7752 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7754 28, 350, 287, 96 // x, y, w, h
7757 45, 561, 460, 152 // x, y, w, h
7761 void oem_upsell_show_screens()
7763 int current_time, k;
7766 if ( !Oem_upsell_bitmaps_loaded ) {
7767 oem_upsell_load_bitmaps();
7768 Oem_upsell_bitmaps_loaded = 1;
7771 // may use upsell screens more than once
7772 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7773 Oem_upsell_screen_number = 0;
7779 int nframes; // used to pass, not really needed (should be 1)
7780 Oem_normal_cursor = gr_get_cursor_bitmap();
7781 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7782 Assert(Oem_web_cursor >= 0);
7783 if (Oem_web_cursor < 0) {
7784 Oem_web_cursor = Oem_normal_cursor;
7789 //oem_reset_trailer_timer();
7791 current_time = timer_get_milliseconds();
7796 // advance screen on keypress or timeout
7797 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7798 oem_upsell_next_screen();
7801 // check if we are done
7802 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7803 Oem_upsell_screen_number--;
7806 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7811 // show me the upsell
7812 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7813 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7817 // if this is the 3rd upsell, make it clickable, d00d
7818 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7820 int button_state = mouse_get_pos(&mx, &my);
7821 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])
7822 && (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]) )
7825 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7828 if (button_state & MOUSE_LEFT_BUTTON) {
7830 multi_pxo_url(OEM_UPSELL_URL);
7834 // switch cursor back to normal one
7835 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7840 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7850 oem_upsell_unload_bitmaps();
7852 // switch cursor back to normal one
7853 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7857 #endif // defined(OEM_BUILD)
7858 // ----------------------------------------------------------------
7860 // OEM UPSELL SCREENS END
7862 // ----------------------------------------------------------------
7866 // ----------------------------------------------------------------
7868 // DEMO UPSELL SCREENS BEGIN
7870 // ----------------------------------------------------------------
7874 //#define NUM_DEMO_UPSELL_SCREENS 4
7876 #define NUM_DEMO_UPSELL_SCREENS 2
7877 #define DEMO_UPSELL_SCREEN_DELAY 3000
7879 static int Demo_upsell_bitmaps_loaded = 0;
7880 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7881 static int Demo_upsell_screen_number = 0;
7882 static int Demo_upsell_show_next_bitmap_time;
7885 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7898 void demo_upsell_next_screen()
7900 Demo_upsell_screen_number++;
7901 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7902 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7904 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7908 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7909 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7910 #ifndef HARDWARE_ONLY
7911 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7918 void demo_upsell_load_bitmaps()
7922 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7923 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7927 void demo_upsell_unload_bitmaps()
7931 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7932 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7933 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7938 Demo_upsell_bitmaps_loaded = 0;
7941 void demo_upsell_show_screens()
7943 int current_time, k;
7946 if ( !Demo_upsell_bitmaps_loaded ) {
7947 demo_upsell_load_bitmaps();
7948 Demo_upsell_bitmaps_loaded = 1;
7951 // may use upsell screens more than once
7952 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7953 Demo_upsell_screen_number = 0;
7960 demo_reset_trailer_timer();
7962 current_time = timer_get_milliseconds();
7969 // don't time out, wait for keypress
7971 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7972 demo_upsell_next_screen();
7977 demo_upsell_next_screen();
7980 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7981 Demo_upsell_screen_number--;
7984 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7989 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7990 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7995 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8005 demo_upsell_unload_bitmaps();
8010 // ----------------------------------------------------------------
8012 // DEMO UPSELL SCREENS END
8014 // ----------------------------------------------------------------
8017 // ----------------------------------------------------------------
8019 // Subspace Ambient Sound START
8021 // ----------------------------------------------------------------
8023 static int Subspace_ambient_left_channel = -1;
8024 static int Subspace_ambient_right_channel = -1;
8027 void game_start_subspace_ambient_sound()
8029 if ( Subspace_ambient_left_channel < 0 ) {
8030 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8033 if ( Subspace_ambient_right_channel < 0 ) {
8034 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8038 void game_stop_subspace_ambient_sound()
8040 if ( Subspace_ambient_left_channel >= 0 ) {
8041 snd_stop(Subspace_ambient_left_channel);
8042 Subspace_ambient_left_channel = -1;
8045 if ( Subspace_ambient_right_channel >= 0 ) {
8046 snd_stop(Subspace_ambient_right_channel);
8047 Subspace_ambient_right_channel = -1;
8051 // ----------------------------------------------------------------
8053 // Subspace Ambient Sound END
8055 // ----------------------------------------------------------------
8057 // ----------------------------------------------------------------
8059 // CDROM detection code START
8061 // ----------------------------------------------------------------
8063 #define CD_SIZE_72_MINUTE_MAX (697000000)
8065 uint game_get_cd_used_space(char *path)
8069 char use_path[512] = "";
8070 char sub_path[512] = "";
8071 WIN32_FIND_DATA find;
8074 // recurse through all files and directories
8075 strcpy(use_path, path);
8076 strcat(use_path, "*.*");
8077 find_handle = FindFirstFile(use_path, &find);
8080 if(find_handle == INVALID_HANDLE_VALUE){
8086 // subdirectory. make sure to ignore . and ..
8087 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8089 strcpy(sub_path, path);
8090 strcat(sub_path, find.cFileName);
8091 strcat(sub_path, "\\");
8092 total += game_get_cd_used_space(sub_path);
8094 total += (uint)find.nFileSizeLow;
8096 } while(FindNextFile(find_handle, &find));
8099 FindClose(find_handle);
8111 // if volume_name is non-null, the CD name must match that
8112 int find_freespace_cd(char *volume_name)
8115 char oldpath[MAX_PATH];
8119 int volume_match = 0;
8123 GetCurrentDirectory(MAX_PATH, oldpath);
8125 for (i = 0; i < 26; i++)
8131 path[0] = (char)('A'+i);
8132 if (GetDriveType(path) == DRIVE_CDROM) {
8134 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8135 nprintf(("CD", "CD volume: %s\n", volume));
8137 // check for any CD volume
8138 int volume1_present = 0;
8139 int volume2_present = 0;
8140 int volume3_present = 0;
8142 char full_check[512] = "";
8144 // look for setup.exe
8145 strcpy(full_check, path);
8146 strcat(full_check, "setup.exe");
8147 find_handle = _findfirst(full_check, &find);
8148 if(find_handle != -1){
8149 volume1_present = 1;
8150 _findclose(find_handle);
8153 // look for intro.mve
8154 strcpy(full_check, path);
8155 strcat(full_check, "intro.mve");
8156 find_handle = _findfirst(full_check, &find);
8157 if(find_handle != -1){
8158 volume2_present = 1;
8159 _findclose(find_handle);
8162 // look for endpart1.mve
8163 strcpy(full_check, path);
8164 strcat(full_check, "endpart1.mve");
8165 find_handle = _findfirst(full_check, &find);
8166 if(find_handle != -1){
8167 volume3_present = 1;
8168 _findclose(find_handle);
8171 // see if we have the specific CD we're looking for
8172 if ( volume_name ) {
8174 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8178 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8182 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8186 if ( volume1_present || volume2_present || volume3_present ) {
8191 // 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
8192 if ( volume_match ){
8194 // 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
8195 if(volume2_present || volume3_present) {
8196 // first step - check to make sure its a cdrom
8197 if(GetDriveType(path) != DRIVE_CDROM){
8201 #if !defined(OEM_BUILD)
8202 // oem not on 80 min cds, so dont check tha size
8204 uint used_space = game_get_cd_used_space(path);
8205 if(used_space < CD_SIZE_72_MINUTE_MAX){
8208 #endif // !defined(OEM_BUILD)
8216 #endif // RELEASE_REAL
8222 SetCurrentDirectory(oldpath);
8231 int set_cdrom_path(int drive_num)
8235 if (drive_num < 0) { //no CD
8237 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8240 strcpy(Game_CDROM_dir,""); //set directory
8244 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8260 i = find_freespace_cd();
8262 rval = set_cdrom_path(i);
8266 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8268 nprintf(("CD", "FreeSpace CD not found\n"));
8276 int Last_cd_label_found = 0;
8277 char Last_cd_label[256];
8279 int game_cd_changed()
8286 if ( strlen(Game_CDROM_dir) == 0 ) {
8290 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8292 if ( found != Last_cd_label_found ) {
8293 Last_cd_label_found = found;
8295 mprintf(( "CD '%s' was inserted\n", label ));
8298 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8302 if ( Last_cd_label_found ) {
8303 if ( !stricmp( Last_cd_label, label )) {
8304 //mprintf(( "CD didn't change\n" ));
8306 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8310 // none found before, none found now.
8311 //mprintf(( "still no CD...\n" ));
8315 Last_cd_label_found = found;
8317 strcpy( Last_cd_label, label );
8319 strcpy( Last_cd_label, "" );
8330 // check if _any_ FreeSpace2 CDs are in the drive
8331 // return: 1 => CD now in drive
8332 // 0 => Could not find CD, they refuse to put it in the drive
8333 int game_do_cd_check(char *volume_name)
8335 #if !defined(GAME_CD_CHECK)
8341 int num_attempts = 0;
8342 int refresh_files = 0;
8344 int path_set_ok, popup_rval;
8346 cd_drive_num = find_freespace_cd(volume_name);
8347 path_set_ok = set_cdrom_path(cd_drive_num);
8348 if ( path_set_ok ) {
8350 if ( refresh_files ) {
8362 // no CD found, so prompt user
8363 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8365 if ( popup_rval != 1 ) {
8370 if ( num_attempts++ > 5 ) {
8381 // check if _any_ FreeSpace2 CDs are in the drive
8382 // return: 1 => CD now in drive
8383 // 0 => Could not find CD, they refuse to put it in the drive
8384 int game_do_cd_check_specific(char *volume_name, int cdnum)
8389 int num_attempts = 0;
8390 int refresh_files = 0;
8392 int path_set_ok, popup_rval;
8394 cd_drive_num = find_freespace_cd(volume_name);
8395 path_set_ok = set_cdrom_path(cd_drive_num);
8396 if ( path_set_ok ) {
8398 if ( refresh_files ) {
8409 // no CD found, so prompt user
8410 #if defined(DVD_MESSAGE_HACK)
8411 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8413 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8416 if ( popup_rval != 1 ) {
8421 if ( num_attempts++ > 5 ) {
8431 // only need to do this in RELEASE_REAL
8432 int game_do_cd_mission_check(char *filename)
8438 fs_builtin_mission *m = game_find_builtin_mission(filename);
8440 // check for changed CD
8441 if(game_cd_changed()){
8446 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8450 // not builtin, so do a general check (any FS2 CD will do)
8452 return game_do_cd_check();
8455 // does not have any CD requirement, do a general check
8456 if(strlen(m->cd_volume) <= 0){
8457 return game_do_cd_check();
8461 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8463 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8465 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8468 return game_do_cd_check();
8471 // did we find the cd?
8472 if(find_freespace_cd(m->cd_volume) >= 0){
8476 // make sure the volume exists
8477 int num_attempts = 0;
8478 int refresh_files = 0;
8480 int path_set_ok, popup_rval;
8482 cd_drive_num = find_freespace_cd(m->cd_volume);
8483 path_set_ok = set_cdrom_path(cd_drive_num);
8484 if ( path_set_ok ) {
8486 if ( refresh_files ) {
8493 // no CD found, so prompt user
8494 #if defined(DVD_MESSAGE_HACK)
8495 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8497 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8501 if ( popup_rval != 1 ) {
8506 if ( num_attempts++ > 5 ) {
8518 // ----------------------------------------------------------------
8520 // CDROM detection code END
8522 // ----------------------------------------------------------------
8524 // ----------------------------------------------------------------
8525 // SHIPS TBL VERIFICATION STUFF
8528 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8529 #define NUM_SHIPS_TBL_CHECKSUMS 1
8531 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8532 -463907578, // US - beta 1
8533 1696074201, // FS2 demo
8536 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8537 // -1022810006, // 1.0 FULL
8538 -1254285366 // 1.2 FULL (German)
8541 void verify_ships_tbl()
8545 Game_ships_tbl_valid = 1;
8551 // detect if the packfile exists
8552 CFILE *detect = cfopen("ships.tbl", "rb");
8553 Game_ships_tbl_valid = 0;
8557 Game_ships_tbl_valid = 0;
8561 // get the long checksum of the file
8563 cfseek(detect, 0, SEEK_SET);
8564 cf_chksum_long(detect, &file_checksum);
8568 // now compare the checksum/filesize against known #'s
8569 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8570 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8571 Game_ships_tbl_valid = 1;
8578 DCF(shipspew, "display the checksum for the current ships.tbl")
8581 CFILE *detect = cfopen("ships.tbl", "rb");
8582 // get the long checksum of the file
8584 cfseek(detect, 0, SEEK_SET);
8585 cf_chksum_long(detect, &file_checksum);
8588 dc_printf("%d", file_checksum);
8591 // ----------------------------------------------------------------
8592 // WEAPONS TBL VERIFICATION STUFF
8595 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8596 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8598 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8599 141718090, // US - beta 1
8600 -266420030, // demo 1
8603 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8604 // 399297860, // 1.0 FULL
8605 -553984927 // 1.2 FULL (german)
8608 void verify_weapons_tbl()
8612 Game_weapons_tbl_valid = 1;
8618 // detect if the packfile exists
8619 CFILE *detect = cfopen("weapons.tbl", "rb");
8620 Game_weapons_tbl_valid = 0;
8624 Game_weapons_tbl_valid = 0;
8628 // get the long checksum of the file
8630 cfseek(detect, 0, SEEK_SET);
8631 cf_chksum_long(detect, &file_checksum);
8635 // now compare the checksum/filesize against known #'s
8636 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8637 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8638 Game_weapons_tbl_valid = 1;
8645 DCF(wepspew, "display the checksum for the current weapons.tbl")
8648 CFILE *detect = cfopen("weapons.tbl", "rb");
8649 // get the long checksum of the file
8651 cfseek(detect, 0, SEEK_SET);
8652 cf_chksum_long(detect, &file_checksum);
8655 dc_printf("%d", file_checksum);
8658 // if the game is running using hacked data
8659 int game_hacked_data()
8662 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8670 void display_title_screen()
8672 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8673 ///int title_bitmap;
8676 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8677 if (title_bitmap == -1) {
8682 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8683 extern void d3d_start_frame();
8688 gr_set_bitmap(title_bitmap);
8694 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8695 extern void d3d_stop_frame();
8702 bm_unload(title_bitmap);
8703 #endif // FS2_DEMO || OEM_BUILD
8706 // return true if the game is running with "low memory", which is less than 48MB
8707 bool game_using_low_mem()
8709 if (Use_low_mem == 0) {