2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.7 2002/05/28 08:52:03 relnev
11 * implemented two assembly stubs.
13 * cleaned up a few warnings.
15 * added a little demo hackery to make it progress a little farther.
17 * Revision 1.6 2002/05/28 06:28:20 theoddone33
18 * Filesystem mods, actually reads some data files now
20 * Revision 1.5 2002/05/28 04:07:28 theoddone33
21 * New graphics stubbing arrangement
23 * Revision 1.4 2002/05/27 22:46:52 theoddone33
24 * Remove more undefined symbols
26 * Revision 1.3 2002/05/26 23:31:18 relnev
27 * added a few files that needed to be compiled
29 * freespace.cpp: now compiles
31 * Revision 1.2 2002/05/07 03:16:44 theoddone33
32 * The Great Newline Fix
34 * Revision 1.1.1.1 2002/05/03 03:28:09 root
38 * 201 6/16/00 3:15p Jefff
39 * sim of the year dvd version changes, a few german soty localization
42 * 200 11/03/99 11:06a Jefff
45 * 199 10/26/99 5:07p Jamest
46 * fixed jeffs dumb debug code
48 * 198 10/25/99 5:53p Jefff
49 * call control_config_common_init() on startup
51 * 197 10/14/99 10:18a Daveb
52 * Fixed incorrect CD checking problem on standalone server.
54 * 196 10/13/99 9:22a Daveb
55 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
56 * related to movies. Fixed launcher spawning from PXO screen.
58 * 195 10/06/99 11:05a Jefff
59 * new oem upsell 3 hotspot coords
61 * 194 10/06/99 10:31a Jefff
64 * 193 10/01/99 9:10a Daveb
67 * 192 9/15/99 4:57a Dave
68 * Updated ships.tbl checksum
70 * 191 9/15/99 3:58a Dave
71 * Removed framerate warning at all times.
73 * 190 9/15/99 3:16a Dave
74 * Remove mt-011.fs2 from the builtin mission list.
76 * 189 9/15/99 1:45a Dave
77 * Don't init joystick on standalone. Fixed campaign mode on standalone.
78 * Fixed no-score-report problem in TvT
80 * 188 9/14/99 6:08a Dave
81 * Updated (final) single, multi, and campaign list.
83 * 187 9/14/99 3:26a Dave
84 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
85 * respawn-too-early problem. Made a few crash points safe.
87 * 186 9/13/99 4:52p Dave
90 * 185 9/12/99 8:09p Dave
91 * Fixed problem where skip-training button would cause mission messages
92 * not to get paged out for the current mission.
94 * 184 9/10/99 11:53a Dave
95 * Shutdown graphics before sound to eliminate apparent lockups when
96 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
98 * 183 9/09/99 11:40p Dave
99 * Handle an Assert() in beam code. Added supernova sounds. Play the right
100 * 2 end movies properly, based upon what the player did in the mission.
102 * 182 9/08/99 10:29p Dave
103 * Make beam sound pausing and unpausing much safer.
105 * 181 9/08/99 10:01p Dave
106 * Make sure game won't run in a drive's root directory. Make sure
107 * standalone routes suqad war messages properly to the host.
109 * 180 9/08/99 3:22p Dave
110 * Updated builtin mission list.
112 * 179 9/08/99 12:01p Jefff
113 * fixed Game_builtin_mission_list typo on Training-2.fs2
115 * 178 9/08/99 9:48a Andsager
116 * Add force feedback for engine wash.
118 * 177 9/07/99 4:01p Dave
119 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
120 * does everything properly (setting up address when binding). Remove
121 * black rectangle background from UI_INPUTBOX.
123 * 176 9/13/99 2:40a Dave
124 * Comment in full 80 minute CD check for RELEASE_REAL builds.
126 * 175 9/06/99 6:38p Dave
127 * Improved CD detection code.
129 * 174 9/06/99 1:30a Dave
130 * Intermediate checkin. Started on enforcing CD-in-drive to play the
133 * 173 9/06/99 1:16a Dave
134 * Make sure the user sees the intro movie.
136 * 172 9/04/99 8:00p Dave
137 * Fixed up 1024 and 32 bit movie support.
139 * 171 9/03/99 1:32a Dave
140 * CD checking by act. Added support to play 2 cutscenes in a row
141 * seamlessly. Fixed super low level cfile bug related to files in the
142 * root directory of a CD. Added cheat code to set campaign mission # in
145 * 170 9/01/99 10:49p Dave
146 * Added nice SquadWar checkbox to the client join wait screen.
148 * 169 9/01/99 10:14a Dave
151 * 168 8/29/99 4:51p Dave
152 * Fixed damaged checkin.
154 * 167 8/29/99 4:18p Andsager
155 * New "burst" limit for friendly damage. Also credit more damage done
156 * against large friendly ships.
158 * 166 8/27/99 6:38p Alanl
159 * crush the blasted repeating messages bug
161 * 164 8/26/99 9:09p Dave
162 * Force framerate check in everything but a RELEASE_REAL build.
164 * 163 8/26/99 9:45a Dave
165 * First pass at easter eggs and cheats.
167 * 162 8/24/99 8:55p Dave
168 * Make sure nondimming pixels work properly in tech menu.
170 * 161 8/24/99 1:49a Dave
171 * Fixed client-side afterburner stuttering. Added checkbox for no version
172 * checking on PXO join. Made button info passing more friendly between
175 * 160 8/22/99 5:53p Dave
176 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
177 * instead of ship designations for multiplayer players.
179 * 159 8/22/99 1:19p Dave
180 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
181 * which d3d cards are detected.
183 * 158 8/20/99 2:09p Dave
184 * PXO banner cycling.
186 * 157 8/19/99 10:59a Dave
187 * Packet loss detection.
189 * 156 8/19/99 10:12a Alanl
190 * preload mission-specific messages on machines greater than 48MB
192 * 155 8/16/99 4:04p Dave
193 * Big honking checkin.
195 * 154 8/11/99 5:54p Dave
196 * Fixed collision problem. Fixed standalone ghost problem.
198 * 153 8/10/99 7:59p Jefff
201 * 152 8/10/99 6:54p Dave
202 * Mad optimizations. Added paging to the nebula effect.
204 * 151 8/10/99 3:44p Jefff
205 * loads Intelligence information on startup
207 * 150 8/09/99 3:47p Dave
208 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
209 * non-nebula missions.
211 * 149 8/09/99 2:21p Andsager
212 * Fix patching from multiplayer direct to launcher update tab.
214 * 148 8/09/99 10:36a Dave
215 * Version info for game.
217 * 147 8/06/99 9:46p Dave
218 * Hopefully final changes for the demo.
220 * 146 8/06/99 3:34p Andsager
221 * Make title version info "(D)" -> "D" show up nicely
223 * 145 8/06/99 2:59p Adamp
224 * Fixed NT launcher/update problem.
226 * 144 8/06/99 1:52p Dave
227 * Bumped up MAX_BITMAPS for the demo.
229 * 143 8/06/99 12:17p Andsager
230 * Demo: down to just 1 demo dog
232 * 142 8/05/99 9:39p Dave
233 * Yet another new checksum.
235 * 141 8/05/99 6:19p Dave
236 * New demo checksums.
238 * 140 8/05/99 5:31p Andsager
239 * Up demo version 1.01
241 * 139 8/05/99 4:22p Andsager
242 * No time limit on upsell screens. Reverse order of display of upsell
245 * 138 8/05/99 4:17p Dave
246 * Tweaks to client interpolation.
248 * 137 8/05/99 3:52p Danw
250 * 136 8/05/99 3:01p Danw
252 * 135 8/05/99 2:43a Anoop
253 * removed duplicate definition.
255 * 134 8/05/99 2:13a Dave
258 * 133 8/05/99 2:05a Dave
261 * 132 8/05/99 1:22a Andsager
264 * 131 8/04/99 9:51p Andsager
265 * Add title screen to demo
267 * 130 8/04/99 6:47p Jefff
268 * fixed link error resulting from #ifdefs
270 * 129 8/04/99 6:26p Dave
271 * Updated ship tbl checksum.
273 * 128 8/04/99 5:40p Andsager
274 * Add multiple demo dogs
276 * 127 8/04/99 5:36p Andsager
277 * Show upsell screens at end of demo campaign before returning to main
280 * 126 8/04/99 11:42a Danw
281 * tone down EAX reverb
283 * 125 8/04/99 11:23a Dave
284 * Updated demo checksums.
286 * 124 8/03/99 11:02p Dave
287 * Maybe fixed sync problems in multiplayer.
289 * 123 8/03/99 6:21p Jefff
292 * 122 8/03/99 3:44p Andsager
293 * Launch laucher if trying to run FS without first having configured
296 * 121 8/03/99 12:45p Dave
299 * 120 8/02/99 9:13p Dave
302 * 119 7/30/99 10:31p Dave
303 * Added comm menu to the configurable hud files.
305 * 118 7/30/99 5:17p Andsager
306 * first fs2demo checksums
308 * 117 7/29/99 3:09p Anoop
310 * 116 7/29/99 12:05a Dave
311 * Nebula speed optimizations.
313 * 115 7/27/99 8:59a Andsager
314 * Make major, minor version consistent for all builds. Only show major
315 * and minor for launcher update window.
317 * 114 7/26/99 5:50p Dave
318 * Revised ingame join. Better? We'll see....
320 * 113 7/26/99 5:27p Andsager
321 * Add training mission as builtin to demo build
323 * 112 7/24/99 1:54p Dave
324 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
327 * 111 7/22/99 4:00p Dave
328 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
330 * 110 7/21/99 8:10p Dave
331 * First run of supernova effect.
333 * 109 7/20/99 1:49p Dave
334 * Peter Drake build. Fixed some release build warnings.
336 * 108 7/19/99 2:26p Andsager
337 * set demo multiplayer missions
339 * 107 7/18/99 5:19p Dave
340 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
342 * 106 7/16/99 1:50p Dave
343 * 8 bit aabitmaps. yay.
345 * 105 7/15/99 3:07p Dave
346 * 32 bit detection support. Mouse coord commandline.
348 * 104 7/15/99 2:13p Dave
349 * Added 32 bit detection.
351 * 103 7/15/99 9:20a Andsager
352 * FS2_DEMO initial checkin
354 * 102 7/14/99 11:02a Dave
355 * Skill level default back to easy. Blech.
357 * 101 7/09/99 5:54p Dave
358 * Seperated cruiser types into individual types. Added tons of new
359 * briefing icons. Campaign screen.
361 * 100 7/08/99 4:43p Andsager
362 * New check for sparky_hi and print if not found.
364 * 99 7/08/99 10:53a Dave
365 * New multiplayer interpolation scheme. Not 100% done yet, but still
366 * better than the old way.
368 * 98 7/06/99 4:24p Dave
369 * Mid-level checkin. Starting on some potentially cool multiplayer
372 * 97 7/06/99 3:35p Andsager
373 * Allow movie to play before red alert mission.
375 * 96 7/03/99 5:50p Dave
376 * Make rotated bitmaps draw properly in padlock views.
378 * 95 7/02/99 9:55p Dave
379 * Player engine wash sound.
381 * 94 7/02/99 4:30p Dave
382 * Much more sophisticated lightning support.
384 * 93 6/29/99 7:52p Dave
385 * Put in exception handling in FS2.
387 * 92 6/22/99 9:37p Dave
388 * Put in pof spewing.
390 * 91 6/16/99 4:06p Dave
391 * New pilot info popup. Added new draw-bitmap-as-poly function.
393 * 90 6/15/99 1:56p Andsager
394 * For release builds, allow start up in high res only with
397 * 89 6/15/99 9:34a Dave
398 * Fixed key checking in single threaded version of the stamp notification
401 * 88 6/09/99 2:55p Andsager
402 * Allow multiple asteroid subtypes (of large, medium, small) and follow
405 * 87 6/08/99 1:14a Dave
406 * Multi colored hud test.
408 * 86 6/04/99 9:52a Dave
409 * Fixed some rendering problems.
411 * 85 6/03/99 10:15p Dave
412 * Put in temporary main hall screen.
414 * 84 6/02/99 6:18p Dave
415 * Fixed TNT lockup problems! Wheeeee!
417 * 83 6/01/99 3:52p Dave
418 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
419 * dead popup, pxo find player popup, pxo private room popup.
421 * 82 5/26/99 1:28p Jasenw
422 * changed coords for loading ani
424 * 81 5/26/99 11:46a Dave
425 * Added ship-blasting lighting and made the randomization of lighting
426 * much more customizable.
428 * 80 5/24/99 5:45p Dave
429 * Added detail levels to the nebula, with a decent speedup. Split nebula
430 * lightning into its own section.
448 #include "systemvars.h"
453 #include "starfield.h"
454 #include "lighting.h"
459 #include "fireballs.h"
463 #include "floating.h"
464 #include "gamesequence.h"
466 #include "optionsmenu.h"
467 #include "playermenu.h"
468 #include "trainingmenu.h"
469 #include "techmenu.h"
472 #include "hudmessage.h"
474 #include "missiongoals.h"
475 #include "missionparse.h"
480 #include "multiutil.h"
481 #include "multimsgs.h"
485 #include "freespace.h"
486 #include "managepilot.h"
488 #include "contexthelp.h"
491 #include "missionbrief.h"
492 #include "missiondebrief.h"
494 #include "missionshipchoice.h"
496 #include "hudconfig.h"
497 #include "controlsconfig.h"
498 #include "missionmessage.h"
499 #include "missiontraining.h"
501 #include "hudtarget.h"
505 #include "eventmusic.h"
506 #include "animplay.h"
507 #include "missionweaponchoice.h"
508 #include "missionlog.h"
509 #include "audiostr.h"
511 #include "missioncampaign.h"
513 #include "missionhotkey.h"
514 #include "objectsnd.h"
515 #include "cmeasure.h"
517 #include "linklist.h"
518 #include "shockwave.h"
519 #include "afterburner.h"
524 #include "stand_gui.h"
525 #include "pcxutils.h"
526 #include "hudtargetbox.h"
527 #include "multi_xfer.h"
528 #include "hudescort.h"
529 #include "multiutil.h"
532 #include "multiteamselect.h"
535 #include "readyroom.h"
536 #include "mainhallmenu.h"
537 #include "multilag.h"
539 #include "particle.h"
541 #include "multi_ingame.h"
542 #include "snazzyui.h"
543 #include "asteroid.h"
544 #include "popupdead.h"
545 #include "multi_voice.h"
546 #include "missioncmdbrief.h"
547 #include "redalert.h"
548 #include "gameplayhelp.h"
549 #include "multilag.h"
550 #include "staticrand.h"
551 #include "multi_pmsg.h"
552 #include "levelpaging.h"
553 #include "observer.h"
554 #include "multi_pause.h"
555 #include "multi_endgame.h"
556 #include "cutscenes.h"
557 #include "multi_respawn.h"
558 // #include "movie.h"
559 #include "multi_obj.h"
560 #include "multi_log.h"
562 #include "localize.h"
563 #include "osregistry.h"
564 #include "barracks.h"
565 #include "missionpause.h"
567 #include "alphacolors.h"
568 #include "objcollide.h"
571 #include "neblightning.h"
572 #include "shipcontrails.h"
575 #include "multi_dogfight.h"
576 #include "multi_rate.h"
577 #include "muzzleflash.h"
581 #include "mainhalltemp.h"
582 #include "exceptionhandler.h"
586 #include "supernova.h"
587 #include "hudshield.h"
588 // #include "names.h"
590 #include "missionloopbrief.h"
594 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
600 // 1.00.04 5/26/98 MWA -- going final (12 pm)
601 // 1.00.03 5/26/98 MWA -- going final (3 am)
602 // 1.00.02 5/25/98 MWA -- going final
603 // 1.00.01 5/25/98 MWA -- going final
604 // 0.90 5/21/98 MWA -- getting ready for final.
605 // 0.10 4/9/98. Set by MK.
607 // Demo version: (obsolete since DEMO codebase split from tree)
608 // 0.03 4/10/98 AL. Interplay rev
609 // 0.02 4/8/98 MK. Increased when this system was modified.
610 // 0.01 4/7/98? AL. First release to Interplay QA.
613 // 1.00 5/28/98 AL. First release to Interplay QA.
615 void game_level_init(int seed = -1);
616 void game_post_level_init();
617 void game_do_frame();
618 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
619 void game_reset_time();
620 void game_show_framerate(); // draws framerate in lower right corner
622 int Game_no_clear = 0;
624 int Pofview_running = 0;
625 int Nebedit_running = 0;
627 typedef struct big_expl_flash {
628 float max_flash_intensity; // max intensity
629 float cur_flash_intensity; // cur intensity
630 int flash_start; // start time
633 #define FRAME_FILTER 16
635 #define DEFAULT_SKILL_LEVEL 1
636 int Game_skill_level = DEFAULT_SKILL_LEVEL;
638 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
639 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
641 #define EXE_FNAME ("fs2.exe")
642 #define LAUNCHER_FNAME ("freespace2.exe")
644 // JAS: Code for warphole camera.
645 // Needs to be cleaned up.
646 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
647 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
648 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
649 matrix Camera_orient = IDENTITY_MATRIX;
650 float Camera_damping = 1.0f;
651 float Camera_time = 0.0f;
652 float Warpout_time = 0.0f;
653 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
654 int Warpout_sound = -1;
656 int Use_joy_mouse = 0;
657 int Use_palette_flash = 1;
659 int Use_fullscreen_at_startup = 0;
661 int Show_area_effect = 0;
662 object *Last_view_target = NULL;
664 int dogfight_blown = 0;
667 float frametimes[FRAME_FILTER];
668 float frametotal = 0.0f;
672 int Show_framerate = 0;
674 int Show_framerate = 1;
677 int Framerate_cap = 120;
680 int Show_target_debug_info = 0;
681 int Show_target_weapons = 0;
683 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
685 int Debug_octant = -1;
687 fix Game_time_compression = F1_0;
689 // if the ships.tbl the player has is valid
690 int Game_ships_tbl_valid = 0;
692 // if the weapons.tbl the player has is valid
693 int Game_weapons_tbl_valid = 0;
697 extern int Player_attacking_enabled;
701 int Pre_player_entry;
703 int Fred_running = 0;
704 char Game_current_mission_filename[MAX_FILENAME_LEN];
705 int game_single_step = 0;
706 int last_single_step=0;
708 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
709 extern int MSG_WINDOW_Y_START;
710 extern int MSG_WINDOW_HEIGHT;
712 int game_zbuffer = 1;
713 //static int Game_music_paused;
714 static int Game_paused;
718 #define EXPIRE_BAD_CHECKSUM 1
719 #define EXPIRE_BAD_TIME 2
721 extern void ssm_init();
722 extern void ssm_level_init();
723 extern void ssm_process();
725 // static variable to contain the time this version was built
726 // commented out for now until
727 // I figure out how to get the username into the file
728 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
730 // defines and variables used for dumping frame for making trailers.
732 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
733 int Debug_dump_trigger = 0;
734 int Debug_dump_frame_count;
735 int Debug_dump_frame_num = 0;
736 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
739 // amount of time to wait after the player has died before we display the death died popup
740 #define PLAYER_DIED_POPUP_WAIT 2500
741 int Player_died_popup_wait = -1;
742 int Player_multi_died_check = -1;
744 // builtin mission list stuff
746 int Game_builtin_mission_count = 6;
747 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
748 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
749 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
750 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
751 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
752 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
753 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
755 #elif defined(PD_BUILD)
756 int Game_builtin_mission_count = 4;
757 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
758 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
759 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
760 { "sm1-01", (FSB_FROM_VOLITION), "" },
761 { "sm1-05", (FSB_FROM_VOLITION), "" },
763 #elif defined(MULTIPLAYER_BETA)
764 int Game_builtin_mission_count = 17;
765 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
767 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
768 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
769 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
770 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
771 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
772 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
773 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
774 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
775 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
776 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
777 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
778 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
779 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
780 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
781 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
782 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
783 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
785 #elif defined(OEM_BUILD)
786 int Game_builtin_mission_count = 17;
787 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
788 // oem version - act 1 only
789 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
792 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
793 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
794 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
795 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
796 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
797 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
798 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
799 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
800 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
801 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
802 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
803 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
804 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
805 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
806 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
807 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
810 int Game_builtin_mission_count = 92;
811 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
812 // single player campaign
813 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
816 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
817 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
818 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
819 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
820 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
822 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
823 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
825 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
826 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
827 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
828 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
829 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
830 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
831 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
832 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
833 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
838 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
839 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
840 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
841 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
850 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
851 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
853 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
854 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
858 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
859 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 // multiplayer missions
865 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
919 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
920 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
921 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
922 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
927 // Internal function prototypes
928 void game_maybe_draw_mouse(float frametime);
929 void init_animating_pointer();
930 void load_animating_pointer(char *filename, int dx, int dy);
931 void unload_animating_pointer();
932 void game_do_training_checks();
933 void game_shutdown(void);
934 void game_show_event_debug(float frametime);
935 void game_event_debug_init();
937 void demo_upsell_show_screens();
938 void game_start_subspace_ambient_sound();
939 void game_stop_subspace_ambient_sound();
940 void verify_ships_tbl();
941 void verify_weapons_tbl();
942 void display_title_screen();
944 // loading background filenames
945 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
946 "LoadingBG", // GR_640
947 "2_LoadingBG" // GR_1024
951 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
952 "Loading.ani", // GR_640
953 "2_Loading.ani" // GR_1024
956 #if defined(FS2_DEMO)
957 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
961 #elif defined(OEM_BUILD)
962 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
969 char Game_CDROM_dir[MAX_PATH_LEN];
972 // How much RAM is on this machine. Set in WinMain
973 uint Freespace_total_ram = 0;
976 float Game_flash_red = 0.0f;
977 float Game_flash_green = 0.0f;
978 float Game_flash_blue = 0.0f;
979 float Sun_spot = 0.0f;
980 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
982 // game shudder stuff (in ms)
983 int Game_shudder_time = -1;
984 int Game_shudder_total = 0;
985 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
988 sound_env Game_sound_env;
989 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
990 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
992 int Game_sound_env_update_timestamp;
994 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
997 // WARPIN CRAP END --------------------------------------------------------------------------------------------
999 fs_builtin_mission *game_find_builtin_mission(char *filename)
1003 // look through all existing builtin missions
1004 for(idx=0; idx<Game_builtin_mission_count; idx++){
1005 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1006 return &Game_builtin_mission_list[idx];
1014 int game_get_default_skill_level()
1016 return DEFAULT_SKILL_LEVEL;
1020 void game_flash_reset()
1022 Game_flash_red = 0.0f;
1023 Game_flash_green = 0.0f;
1024 Game_flash_blue = 0.0f;
1026 Big_expl_flash.max_flash_intensity = 0.0f;
1027 Big_expl_flash.cur_flash_intensity = 0.0f;
1028 Big_expl_flash.flash_start = 0;
1031 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1032 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1034 void game_framerate_check_init()
1036 // zero critical time
1037 Gf_critical_time = 0.0f;
1040 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1041 // if this is a glide card
1042 if(gr_screen.mode == GR_GLIDE){
1044 extern GrHwConfiguration hwconfig;
1047 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1048 Gf_critical = 15.0f;
1052 Gf_critical = 10.0f;
1057 Gf_critical = 15.0f;
1060 // d3d. only care about good cards here I guess (TNT)
1062 Gf_critical = 15.0f;
1065 // if this is a glide card
1066 if(gr_screen.mode == GR_GLIDE){
1068 extern GrHwConfiguration hwconfig;
1071 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1072 Gf_critical = 25.0f;
1076 Gf_critical = 20.0f;
1081 Gf_critical = 25.0f;
1084 // d3d. only care about good cards here I guess (TNT)
1086 Gf_critical = 25.0f;
1091 extern float Framerate;
1092 void game_framerate_check()
1096 // if the current framerate is above the critical level, add frametime
1097 if(Framerate >= Gf_critical){
1098 Gf_critical_time += flFrametime;
1101 if(!Show_framerate){
1105 // display if we're above the critical framerate
1106 if(Framerate < Gf_critical){
1107 gr_set_color_fast(&Color_bright_red);
1108 gr_string(200, y_start, "Framerate warning");
1113 // display our current pct of good frametime
1114 if(f2fl(Missiontime) >= 0.0f){
1115 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1118 gr_set_color_fast(&Color_bright_green);
1120 gr_set_color_fast(&Color_bright_red);
1123 gr_printf(200, y_start, "%d%%", (int)pct);
1130 // Adds a flash effect. These can be positive or negative.
1131 // The range will get capped at around -1 to 1, so stick
1132 // with a range like that.
1133 void game_flash( float r, float g, float b )
1135 Game_flash_red += r;
1136 Game_flash_green += g;
1137 Game_flash_blue += b;
1139 if ( Game_flash_red < -1.0f ) {
1140 Game_flash_red = -1.0f;
1141 } else if ( Game_flash_red > 1.0f ) {
1142 Game_flash_red = 1.0f;
1145 if ( Game_flash_green < -1.0f ) {
1146 Game_flash_green = -1.0f;
1147 } else if ( Game_flash_green > 1.0f ) {
1148 Game_flash_green = 1.0f;
1151 if ( Game_flash_blue < -1.0f ) {
1152 Game_flash_blue = -1.0f;
1153 } else if ( Game_flash_blue > 1.0f ) {
1154 Game_flash_blue = 1.0f;
1159 // Adds a flash for Big Ship explosions
1160 // cap range from 0 to 1
1161 void big_explosion_flash(float flash)
1163 Big_expl_flash.flash_start = timestamp(1);
1167 } else if (flash < 0.0f) {
1171 Big_expl_flash.max_flash_intensity = flash;
1172 Big_expl_flash.cur_flash_intensity = 0.0f;
1175 // Amount to diminish palette towards normal, per second.
1176 #define DIMINISH_RATE 0.75f
1177 #define SUN_DIMINISH_RATE 6.00f
1181 float sn_glare_scale = 1.7f;
1184 dc_get_arg(ARG_FLOAT);
1185 sn_glare_scale = Dc_arg_float;
1188 float Supernova_last_glare = 0.0f;
1189 void game_sunspot_process(float frametime)
1193 float Sun_spot_goal = 0.0f;
1196 sn_stage = supernova_active();
1198 // sunspot differently based on supernova stage
1200 // approaching. player still in control
1203 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1206 light_get_global_dir(&light_dir, 0);
1208 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1211 // scale it some more
1212 dot = dot * (0.5f + (pct * 0.5f));
1215 Sun_spot_goal += (dot * sn_glare_scale);
1218 // draw the sun glow
1219 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1220 // draw the glow for this sun
1221 stars_draw_sun_glow(0);
1224 Supernova_last_glare = Sun_spot_goal;
1227 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1230 Sun_spot_goal = 0.9f;
1231 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1233 if(Sun_spot_goal > 1.0f){
1234 Sun_spot_goal = 1.0f;
1237 Sun_spot_goal *= sn_glare_scale;
1238 Supernova_last_glare = Sun_spot_goal;
1241 // fade to white. display dead popup
1244 Supernova_last_glare += (2.0f * flFrametime);
1245 if(Supernova_last_glare > 2.0f){
1246 Supernova_last_glare = 2.0f;
1249 Sun_spot_goal = Supernova_last_glare;
1256 // check sunspots for all suns
1257 n_lights = light_get_global_count();
1260 for(idx=0; idx<n_lights; idx++){
1261 //(vector *eye_pos, matrix *eye_orient)
1262 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1265 light_get_global_dir(&light_dir, idx);
1267 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1269 Sun_spot_goal += (float)pow(dot,85.0f);
1271 // draw the glow for this sun
1272 stars_draw_sun_glow(idx);
1274 Sun_spot_goal = 0.0f;
1280 Sun_spot_goal = 0.0f;
1284 float dec_amount = frametime*SUN_DIMINISH_RATE;
1286 if ( Sun_spot < Sun_spot_goal ) {
1287 Sun_spot += dec_amount;
1288 if ( Sun_spot > Sun_spot_goal ) {
1289 Sun_spot = Sun_spot_goal;
1291 } else if ( Sun_spot > Sun_spot_goal ) {
1292 Sun_spot -= dec_amount;
1293 if ( Sun_spot < Sun_spot_goal ) {
1294 Sun_spot = Sun_spot_goal;
1300 // Call once a frame to diminish the
1301 // flash effect to 0.
1302 void game_flash_diminish(float frametime)
1304 float dec_amount = frametime*DIMINISH_RATE;
1306 if ( Game_flash_red > 0.0f ) {
1307 Game_flash_red -= dec_amount;
1308 if ( Game_flash_red < 0.0f )
1309 Game_flash_red = 0.0f;
1311 Game_flash_red += dec_amount;
1312 if ( Game_flash_red > 0.0f )
1313 Game_flash_red = 0.0f;
1316 if ( Game_flash_green > 0.0f ) {
1317 Game_flash_green -= dec_amount;
1318 if ( Game_flash_green < 0.0f )
1319 Game_flash_green = 0.0f;
1321 Game_flash_green += dec_amount;
1322 if ( Game_flash_green > 0.0f )
1323 Game_flash_green = 0.0f;
1326 if ( Game_flash_blue > 0.0f ) {
1327 Game_flash_blue -= dec_amount;
1328 if ( Game_flash_blue < 0.0f )
1329 Game_flash_blue = 0.0f;
1331 Game_flash_blue += dec_amount;
1332 if ( Game_flash_blue > 0.0f )
1333 Game_flash_blue = 0.0f;
1336 // update big_explosion_cur_flash
1337 #define TIME_UP 1500
1338 #define TIME_DOWN 2500
1339 int duration = TIME_UP + TIME_DOWN;
1340 int time = timestamp_until(Big_expl_flash.flash_start);
1341 if (time > -duration) {
1343 if (time < TIME_UP) {
1344 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1347 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1351 if ( Use_palette_flash ) {
1353 // static int or=0, og=0, ob=0;
1355 // Change the 200 to change the color range of colors.
1356 r = fl2i( Game_flash_red*128.0f );
1357 g = fl2i( Game_flash_green*128.0f );
1358 b = fl2i( Game_flash_blue*128.0f );
1360 if ( Sun_spot > 0.0f ) {
1361 r += fl2i(Sun_spot*128.0f);
1362 g += fl2i(Sun_spot*128.0f);
1363 b += fl2i(Sun_spot*128.0f);
1366 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1367 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1368 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1369 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1372 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1373 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1374 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1376 if ( (r!=0) || (g!=0) || (b!=0) ) {
1377 gr_flash( r, g, b );
1379 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1390 void game_level_close()
1392 // De-Initialize the game subsystems
1393 message_mission_shutdown();
1394 event_music_level_close();
1395 game_stop_looped_sounds();
1397 obj_snd_level_close(); // uninit object-linked persistant sounds
1398 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1399 anim_level_close(); // stop and clean up any anim instances
1400 shockwave_level_close();
1401 fireball_level_close();
1403 mission_event_shutdown();
1404 asteroid_level_close();
1405 model_cache_reset(); // Reset/free all the model caching stuff
1406 flak_level_close(); // unload flak stuff
1407 neb2_level_close(); // shutdown gaseous nebula stuff
1410 mflash_level_close();
1412 audiostream_unpause_all();
1417 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1418 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1419 void game_level_init(int seed)
1421 // seed the random number generator
1423 // if no seed was passed, seed the generator either from the time value, or from the
1424 // netgame security flags -- ensures that all players in multiplayer game will have the
1425 // same randon number sequence (with static rand functions)
1426 if ( Game_mode & GM_NORMAL ) {
1427 Game_level_seed = time(NULL);
1429 Game_level_seed = Netgame.security;
1432 // mwa 9/17/98 -- maybe this assert isn't needed????
1433 Assert( !(Game_mode & GM_MULTIPLAYER) );
1434 Game_level_seed = seed;
1436 srand( Game_level_seed );
1438 // semirand function needs to get re-initted every time in multiplayer
1439 if ( Game_mode & GM_MULTIPLAYER ){
1445 Key_normal_game = (Game_mode & GM_NORMAL);
1448 Game_shudder_time = -1;
1450 // Initialize the game subsystems
1451 // timestamp_reset(); // Must be inited before everything else
1453 game_reset_time(); // resets time, and resets saved time too
1455 obj_init(); // Must be inited before the other systems
1456 model_free_all(); // Free all existing models
1457 mission_brief_common_init(); // Free all existing briefing/debriefing text
1458 weapon_level_init();
1459 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1461 player_level_init();
1462 shipfx_flash_init(); // Init the ship gun flash system.
1463 game_flash_reset(); // Reset the flash effect
1464 particle_init(); // Reset the particle system
1468 shield_hit_init(); // Initialize system for showing shield hits
1469 radar_mission_init();
1470 mission_init_goals();
1473 obj_snd_level_init(); // init object-linked persistant sounds
1475 shockwave_level_init();
1476 afterburner_level_init();
1477 scoring_level_init( &Player->stats );
1479 asteroid_level_init();
1480 control_config_clear_used_status();
1481 collide_ship_ship_sounds_init();
1483 Pre_player_entry = 1; // Means the player has not yet entered.
1484 Entry_delay_time = 0; // Could get overwritten in mission read.
1485 fireball_preload(); // page in warphole bitmaps
1487 flak_level_init(); // initialize flak - bitmaps, etc
1488 ct_level_init(); // initialize ships contrails, etc
1489 awacs_level_init(); // initialize AWACS
1490 beam_level_init(); // initialize beam weapons
1491 mflash_level_init();
1493 supernova_level_init();
1495 // multiplayer dogfight hack
1498 shipfx_engine_wash_level_init();
1502 Last_view_target = NULL;
1507 // campaign wasn't ended
1508 Campaign_ended_in_mission = 0;
1511 // called when a mission is over -- does server specific stuff.
1512 void freespace_stop_mission()
1515 Game_mode &= ~GM_IN_MISSION;
1518 // called at frame interval to process networking stuff
1519 void game_do_networking()
1521 Assert( Net_player != NULL );
1522 if (!(Game_mode & GM_MULTIPLAYER)){
1526 // see if this player should be reading/writing data. Bit is set when at join
1527 // screen onward until quits back to main menu.
1528 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1532 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1535 multi_pause_do_frame();
1540 // Loads the best palette for this level, based
1541 // on nebula color and hud color. You could just call palette_load_table with
1542 // the appropriate filename, but who wants to do that.
1543 void game_load_palette()
1545 char palette_filename[1024];
1547 // We only use 3 hud colors right now
1548 // Assert( HUD_config.color >= 0 );
1549 // Assert( HUD_config.color <= 2 );
1551 Assert( Mission_palette >= 0 );
1552 Assert( Mission_palette <= 98 );
1554 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1555 strcpy( palette_filename, NOX("gamepalette-subspace") );
1557 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1560 mprintf(( "Loading palette %s\n", palette_filename ));
1562 // palette_load_table(palette_filename);
1565 void game_post_level_init()
1567 // Stuff which gets called after mission is loaded. Because player isn't created until
1568 // after mission loads, some things must get initted after the level loads
1570 model_level_post_init();
1573 hud_setup_escort_list();
1574 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1580 game_event_debug_init();
1583 training_mission_init();
1584 asteroid_create_all();
1586 game_framerate_check_init();
1590 // An estimate as to how high the count passed to game_loading_callback will go.
1591 // This is just a guess, it seems to always be about the same. The count is
1592 // proportional to the code being executed, not the time, so this works good
1593 // for a bar, assuming the code does about the same thing each time you
1594 // load a level. You can find this value by looking at the return value
1595 // of game_busy_callback(NULL), which I conveniently print out to the
1596 // debug output window with the '=== ENDING LOAD ==' stuff.
1597 //#define COUNT_ESTIMATE 3706
1598 #define COUNT_ESTIMATE 1111
1600 int Game_loading_callback_inited = 0;
1602 int Game_loading_background = -1;
1603 anim * Game_loading_ani = NULL;
1604 anim_instance *Game_loading_ani_instance;
1605 int Game_loading_frame=-1;
1607 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1616 // This gets called 10x per second and count is the number of times
1617 // game_busy() has been called since the current callback function
1619 void game_loading_callback(int count)
1621 game_do_networking();
1623 Assert( Game_loading_callback_inited==1 );
1624 Assert( Game_loading_ani != NULL );
1626 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1627 if ( framenum > Game_loading_ani->total_frames-1 ) {
1628 framenum = Game_loading_ani->total_frames-1;
1629 } else if ( framenum < 0 ) {
1634 while ( Game_loading_frame < framenum ) {
1635 Game_loading_frame++;
1636 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1640 if ( cbitmap > -1 ) {
1641 if ( Game_loading_background > -1 ) {
1642 gr_set_bitmap( Game_loading_background );
1646 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1647 gr_set_bitmap( cbitmap );
1648 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1650 bm_release(cbitmap);
1656 void game_loading_callback_init()
1658 Assert( Game_loading_callback_inited==0 );
1660 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1661 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1664 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1665 Assert( Game_loading_ani != NULL );
1666 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1667 Assert( Game_loading_ani_instance != NULL );
1668 Game_loading_frame = -1;
1670 Game_loading_callback_inited = 1;
1672 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1677 void game_loading_callback_close()
1679 Assert( Game_loading_callback_inited==1 );
1681 // Make sure bar shows all the way over.
1682 game_loading_callback(COUNT_ESTIMATE);
1684 int real_count = game_busy_callback( NULL );
1687 Game_loading_callback_inited = 0;
1690 mprintf(( "=================== ENDING LOAD ================\n" ));
1691 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1692 mprintf(( "================================================\n" ));
1694 // to remove warnings in release build
1698 free_anim_instance(Game_loading_ani_instance);
1699 Game_loading_ani_instance = NULL;
1700 anim_free(Game_loading_ani);
1701 Game_loading_ani = NULL;
1703 bm_release( Game_loading_background );
1704 common_free_interface_palette(); // restore game palette
1705 Game_loading_background = -1;
1707 gr_set_font( FONT1 );
1710 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1712 void game_maybe_update_sound_environment()
1714 // do nothing for now
1717 // Assign the sound environment for the game, based on the current mission
1719 void game_assign_sound_environment()
1722 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1723 Game_sound_env.id = SND_ENV_DRUGGED;
1724 Game_sound_env.volume = 0.800f;
1725 Game_sound_env.damping = 1.188f;
1726 Game_sound_env.decay = 6.392f;
1728 } else if (Num_asteroids > 30) {
1729 Game_sound_env.id = SND_ENV_AUDITORIUM;
1730 Game_sound_env.volume = 0.603f;
1731 Game_sound_env.damping = 0.5f;
1732 Game_sound_env.decay = 4.279f;
1735 Game_sound_env = Game_default_sound_env;
1739 Game_sound_env = Game_default_sound_env;
1740 Game_sound_env_update_timestamp = timestamp(1);
1743 // function which gets called before actually entering the mission. It is broken down into a funciton
1744 // since it will get called in one place from a single player game and from another place for
1745 // a multiplayer game
1746 void freespace_mission_load_stuff()
1748 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1749 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1750 if(!(Game_mode & GM_STANDALONE_SERVER)){
1752 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1754 game_loading_callback_init();
1756 event_music_level_init(); // preloads the first 2 seconds for each event music track
1759 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1762 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1765 ship_assign_sound_all(); // assign engine sounds to ships
1766 game_assign_sound_environment(); // assign the sound environment for this mission
1769 // call function in missionparse.cpp to fixup player/ai stuff.
1770 mission_parse_fixup_players();
1773 // Load in all the bitmaps for this level
1778 game_loading_callback_close();
1780 // the only thing we need to call on the standalone for now.
1782 // call function in missionparse.cpp to fixup player/ai stuff.
1783 mission_parse_fixup_players();
1785 // Load in all the bitmaps for this level
1791 uint load_mission_load;
1792 uint load_post_level_init;
1793 uint load_mission_stuff;
1795 // tells the server to load the mission and initialize structures
1796 int game_start_mission()
1798 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1800 load_gl_init = time(NULL);
1802 load_gl_init = time(NULL) - load_gl_init;
1804 if (Game_mode & GM_MULTIPLAYER) {
1805 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1807 // clear multiplayer stats
1808 init_multiplayer_stats();
1811 load_mission_load = time(NULL);
1812 if (mission_load()) {
1813 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1814 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1815 gameseq_post_event(GS_EVENT_MAIN_MENU);
1817 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1822 load_mission_load = time(NULL) - load_mission_load;
1824 // If this is a red alert mission in campaign mode, bash wingman status
1825 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1826 red_alert_bash_wingman_status();
1829 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1830 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1831 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1832 // game_load_palette();
1835 load_post_level_init = time(NULL);
1836 game_post_level_init();
1837 load_post_level_init = time(NULL) - load_post_level_init;
1841 void Do_model_timings_test();
1842 Do_model_timings_test();
1846 load_mission_stuff = time(NULL);
1847 freespace_mission_load_stuff();
1848 load_mission_stuff = time(NULL) - load_mission_stuff;
1853 int Interface_framerate = 0;
1856 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1857 DCF_BOOL( show_framerate, Show_framerate )
1858 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1859 DCF_BOOL( show_target_weapons, Show_target_weapons )
1860 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1861 DCF_BOOL( sound, Sound_enabled )
1862 DCF_BOOL( zbuffer, game_zbuffer )
1863 DCF_BOOL( shield_system, New_shield_system )
1864 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1865 DCF_BOOL( player_attacking, Player_attacking_enabled )
1866 DCF_BOOL( show_waypoints, Show_waypoints )
1867 DCF_BOOL( show_area_effect, Show_area_effect )
1868 DCF_BOOL( show_net_stats, Show_net_stats )
1869 DCF_BOOL( log, Log_debug_output_to_file )
1870 DCF_BOOL( training_msg_method, Training_msg_method )
1871 DCF_BOOL( show_player_pos, Show_player_pos )
1872 DCF_BOOL(i_framerate, Interface_framerate )
1874 DCF(show_mem,"Toggles showing mem usage")
1877 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1878 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1879 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1880 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1886 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1888 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1889 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1893 DCF(show_cpu,"Toggles showing cpu usage")
1896 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1897 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1898 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1899 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1905 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1907 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1908 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1915 // AL 4-8-98: always allow players to display their framerate
1918 DCF_BOOL( show_framerate, Show_framerate )
1925 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1928 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1929 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1930 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1931 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1933 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" );
1934 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1936 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1939 DCF(palette_flash,"Toggles palette flash effect on/off")
1942 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1943 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1944 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1945 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1947 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1948 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1951 int Use_low_mem = 0;
1953 DCF(low_mem,"Uses low memory settings regardless of RAM")
1956 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1957 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1958 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1959 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1961 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1962 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1964 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1970 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1973 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1974 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1975 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1976 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1978 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1979 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1980 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1984 int Framerate_delay = 0;
1986 float Freespace_gamma = 1.0f;
1988 DCF(gamma,"Sets Gamma factor")
1991 dc_get_arg(ARG_FLOAT|ARG_NONE);
1992 if ( Dc_arg_type & ARG_FLOAT ) {
1993 Freespace_gamma = Dc_arg_float;
1995 dc_printf( "Gamma reset to 1.0f\n" );
1996 Freespace_gamma = 1.0f;
1998 if ( Freespace_gamma < 0.1f ) {
1999 Freespace_gamma = 0.1f;
2000 } else if ( Freespace_gamma > 5.0f ) {
2001 Freespace_gamma = 5.0f;
2003 gr_set_gamma(Freespace_gamma);
2005 char tmp_gamma_string[32];
2006 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2007 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2011 dc_printf( "Usage: gamma <float>\n" );
2012 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2013 Dc_status = 0; // don't print status if help is printed. Too messy.
2017 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2026 Game_current_mission_filename[0] = 0;
2028 // seed the random number generator
2029 Game_init_seed = time(NULL);
2030 srand( Game_init_seed );
2032 Framerate_delay = 0;
2038 extern void bm_init();
2044 // Initialize the timer before the os
2052 GetCurrentDirectory(1024, whee);
2055 getcwd (whee, 1024);
2058 strcat(whee, EXE_FNAME);
2060 //Initialize the libraries
2061 s1 = timer_get_milliseconds();
2062 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2065 e1 = timer_get_milliseconds();
2067 // time a bunch of cfopens
2069 s2 = timer_get_milliseconds();
2071 for(int idx=0; idx<10000; idx++){
2072 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2077 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2079 e2 = timer_get_milliseconds();
2082 if (Is_standalone) {
2083 std_init_standalone();
2085 os_init( Osreg_class_name, Osreg_app_name );
2086 os_set_title(Osreg_title);
2089 // initialize localization module. Make sure this is down AFTER initialzing OS.
2090 // int t1 = timer_get_milliseconds();
2093 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2095 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2098 // verify that he has a valid weapons.tbl
2099 verify_weapons_tbl();
2101 // Output version numbers to registry for auto patching purposes
2102 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2103 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2104 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2106 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2107 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2108 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2111 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2115 Asteroids_enabled = 1;
2118 /////////////////////////////
2120 /////////////////////////////
2125 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2126 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2128 if (!stricmp(ptr, NOX("no sound"))) {
2129 Cmdline_freespace_no_sound = 1;
2131 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2133 } else if (!stricmp(ptr, NOX("EAX"))) {
2138 if (!Is_standalone) {
2139 snd_init(use_a3d, use_eax);
2141 /////////////////////////////
2143 /////////////////////////////
2145 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2148 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);
2150 // fire up the UpdateLauncher executable
2152 PROCESS_INFORMATION pi;
2154 memset( &si, 0, sizeof(STARTUPINFO) );
2157 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2158 NULL, // pointer to command line string
2159 NULL, // pointer to process security attributes
2160 NULL, // pointer to thread security attributes
2161 FALSE, // handle inheritance flag
2162 CREATE_DEFAULT_ERROR_MODE, // creation flags
2163 NULL, // pointer to new environment block
2164 NULL, // pointer to current directory name
2165 &si, // pointer to STARTUPINFO
2166 &pi // pointer to PROCESS_INFORMATION
2169 // If the Launcher could not be started up, let the user know
2171 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2180 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2182 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);
2190 // check for hi res pack file
2191 int has_sparky_hi = 0;
2193 // check if sparky_hi exists -- access mode 0 means does file exist
2196 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2199 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2202 // see if we've got 32 bit in the string
2203 if(strstr(ptr, "32 bit")){
2209 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2211 // always 640 for E3
2212 gr_init(GR_640, GR_GLIDE);
2214 // regular or hi-res ?
2216 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2218 if(strstr(ptr, NOX("(1024x768)"))){
2220 gr_init(GR_1024, GR_GLIDE);
2222 gr_init(GR_640, GR_GLIDE);
2225 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2227 // always 640 for E3
2229 gr_init(GR_640, GR_DIRECT3D, depth);
2231 // regular or hi-res ?
2233 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2235 if(strstr(ptr, NOX("(1024x768)"))){
2239 gr_init(GR_1024, GR_DIRECT3D, depth);
2243 gr_init(GR_640, GR_DIRECT3D, depth);
2249 if ( Use_fullscreen_at_startup && !Is_standalone) {
2250 gr_init(GR_640, GR_DIRECTDRAW);
2252 gr_init(GR_640, GR_SOFTWARE);
2255 if ( !Is_standalone ) {
2256 gr_init(GR_640, GR_DIRECTDRAW);
2258 gr_init(GR_640, GR_SOFTWARE);
2264 extern int Gr_inited;
2265 if(trying_d3d && !Gr_inited){
2266 extern char Device_init_error[512];
2268 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2277 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2278 Freespace_gamma = (float)atof(ptr);
2279 if ( Freespace_gamma < 0.1f ) {
2280 Freespace_gamma = 0.1f;
2281 } else if ( Freespace_gamma > 5.0f ) {
2282 Freespace_gamma = 5.0f;
2284 char tmp_gamma_string[32];
2285 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2286 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2288 gr_set_gamma(Freespace_gamma);
2290 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2293 display_title_screen();
2297 // attempt to load up master tracker registry info (login and password)
2298 Multi_tracker_id = -1;
2300 // pxo login and password
2301 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2303 nprintf(("Network","Error reading in PXO login data\n"));
2304 strcpy(Multi_tracker_login,"");
2306 strcpy(Multi_tracker_login,ptr);
2308 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2310 nprintf(("Network","Error reading PXO password\n"));
2311 strcpy(Multi_tracker_passwd,"");
2313 strcpy(Multi_tracker_passwd,ptr);
2316 // pxo squad name and password
2317 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2319 nprintf(("Network","Error reading in PXO squad name\n"));
2320 strcpy(Multi_tracker_squad_name, "");
2322 strcpy(Multi_tracker_squad_name, ptr);
2325 // If less than 48MB of RAM, use low memory model.
2326 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2327 mprintf(( "Using normal memory settings...\n" ));
2328 bm_set_low_mem(1); // Use every other frame of bitmaps
2330 mprintf(( "Using high memory settings...\n" ));
2331 bm_set_low_mem(0); // Use all frames of bitmaps
2334 // load non-darkening pixel defs
2335 palman_load_pixels();
2337 // hud shield icon stuff
2338 hud_shield_game_init();
2340 control_config_common_init(); // sets up localization stuff in the control config
2346 gamesnd_parse_soundstbl();
2351 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2356 player_controls_init();
2359 //if(!Is_standalone){
2367 ship_init(); // read in ships.tbl
2369 mission_campaign_init(); // load in the default campaign
2371 // navmap_init(); // init the navigation map system
2372 context_help_init();
2373 techroom_intel_init(); // parse species.tbl, load intel info
2375 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2376 init_animating_pointer();
2378 mission_brief_common_init(); // Mark all the briefing structures as empty.
2379 gr_font_init(); // loads up all fonts
2381 neb2_init(); // fullneb stuff
2385 player_tips_init(); // helpful tips
2388 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2389 pilot_load_pic_list();
2390 pilot_load_squad_pic_list();
2392 load_animating_pointer(NOX("cursor"), 0, 0);
2394 // initialize alpha colors
2395 alpha_colors_init();
2398 // Game_music_paused = 0;
2405 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2406 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2408 mprintf(("cfile_init() took %d\n", e1 - s1));
2409 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2412 char transfer_text[128];
2414 float Start_time = 0.0f;
2416 float Framerate = 0.0f;
2418 float Timing_total = 0.0f;
2419 float Timing_render2 = 0.0f;
2420 float Timing_render3 = 0.0f;
2421 float Timing_flip = 0.0f;
2422 float Timing_clear = 0.0f;
2424 MONITOR(NumPolysDrawn);
2430 void game_get_framerate()
2432 char text[128] = "";
2434 if ( frame_int == -1 ) {
2436 for (i=0; i<FRAME_FILTER; i++ ) {
2437 frametimes[i] = 0.0f;
2442 frametotal -= frametimes[frame_int];
2443 frametotal += flFrametime;
2444 frametimes[frame_int] = flFrametime;
2445 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2447 if ( frametotal != 0.0 ) {
2448 if ( Framecount >= FRAME_FILTER )
2449 Framerate = FRAME_FILTER / frametotal;
2451 Framerate = Framecount / frametotal;
2452 sprintf( text, NOX("FPS: %.1f"), Framerate );
2454 sprintf( text, NOX("FPS: ?") );
2458 if (Show_framerate) {
2459 gr_set_color_fast(&HUD_color_debug);
2460 gr_string( 570, 2, text );
2464 void game_show_framerate()
2468 cur_time = f2fl(timer_get_approx_seconds());
2469 if (cur_time - Start_time > 30.0f) {
2470 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2471 Start_time += 1000.0f;
2474 //mprintf(( "%s\n", text ));
2477 if ( Debug_dump_frames )
2481 // possibly show control checking info
2482 control_check_indicate();
2484 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2485 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2486 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2487 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2490 if ( Show_cpu == 1 ) {
2495 dy = gr_get_font_height() + 1;
2497 gr_set_color_fast(&HUD_color_debug);
2501 extern int D3D_textures_in;
2502 extern int D3D_textures_in_frame;
2503 extern int Glide_textures_in;
2504 extern int Glide_textures_in_frame;
2505 extern int Glide_explosion_vram;
2506 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2508 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2510 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2516 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2518 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2520 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2522 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2524 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2529 extern int Num_pairs; // Number of object pairs that were checked.
2530 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2533 extern int Num_pairs_checked; // What percent of object pairs were checked.
2534 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2536 Num_pairs_checked = 0;
2540 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2543 if ( Timing_total > 0.01f ) {
2544 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2546 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2548 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2550 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2552 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2562 dy = gr_get_font_height() + 1;
2564 gr_set_color_fast(&HUD_color_debug);
2567 extern int TotalRam;
2568 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2573 extern int Model_ram;
2574 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2578 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2580 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2582 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2586 extern int D3D_textures_in;
2587 extern int Glide_textures_in;
2588 extern int Glide_textures_in_frame;
2589 extern int Glide_explosion_vram;
2590 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2592 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2594 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2603 if ( Show_player_pos ) {
2607 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));
2610 MONITOR_INC(NumPolys, modelstats_num_polys);
2611 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2612 MONITOR_INC(NumVerts, modelstats_num_verts );
2614 modelstats_num_polys = 0;
2615 modelstats_num_polys_drawn = 0;
2616 modelstats_num_verts = 0;
2617 modelstats_num_sortnorms = 0;
2621 void game_show_standalone_framerate()
2623 float frame_rate=30.0f;
2624 if ( frame_int == -1 ) {
2626 for (i=0; i<FRAME_FILTER; i++ ) {
2627 frametimes[i] = 0.0f;
2632 frametotal -= frametimes[frame_int];
2633 frametotal += flFrametime;
2634 frametimes[frame_int] = flFrametime;
2635 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2637 if ( frametotal != 0.0 ) {
2638 if ( Framecount >= FRAME_FILTER ){
2639 frame_rate = FRAME_FILTER / frametotal;
2641 frame_rate = Framecount / frametotal;
2644 std_set_standalone_fps(frame_rate);
2648 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2649 void game_show_time_left()
2653 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2654 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2655 // checking how much time is left
2657 if ( Mission_end_time == -1 ){
2661 diff = f2i(Mission_end_time - Missiontime);
2662 // be sure to bash to 0. diff could be negative on frame that we quit mission
2667 hud_set_default_color();
2668 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2671 //========================================================================================
2672 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2673 //========================================================================================
2677 DCF(ai_pause,"Pauses ai")
2680 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2681 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2682 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2683 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2686 obj_init_all_ships_physics();
2689 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2690 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2693 DCF(single_step,"Single steps the game")
2696 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2697 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2698 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2699 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2701 last_single_step = 0; // Make so single step waits a frame before stepping
2704 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2705 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2708 DCF_BOOL(physics_pause, physics_paused)
2709 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2710 DCF_BOOL(ai_firing, Ai_firing_enabled )
2712 // Create some simple aliases to these commands...
2713 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2714 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2715 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2716 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2717 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2720 //========================================================================================
2721 //========================================================================================
2724 void game_training_pause_do()
2728 key = game_check_key();
2730 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2737 void game_increase_skill_level()
2740 if (Game_skill_level >= NUM_SKILL_LEVELS){
2741 Game_skill_level = 0;
2745 int Player_died_time;
2747 int View_percent = 100;
2750 DCF(view, "Sets the percent of the 3d view to render.")
2753 dc_get_arg(ARG_INT);
2754 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2755 View_percent = Dc_arg_int;
2757 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2763 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2767 dc_printf("View is set to %d%%\n", View_percent );
2772 // Set the clip region for the 3d rendering window
2773 void game_set_view_clip()
2775 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2776 // Set the clip region for the letterbox "dead view"
2777 int yborder = gr_screen.max_h/4;
2779 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2780 // J.S. I've changed my ways!! See the new "no constants" code!!!
2781 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2783 // Set the clip region for normal view
2784 if ( View_percent >= 100 ) {
2787 int xborder, yborder;
2789 if ( View_percent < 5 ) {
2793 float fp = i2fl(View_percent)/100.0f;
2794 int fi = fl2i(fl_sqrt(fp)*100.0f);
2795 if ( fi > 100 ) fi=100;
2797 xborder = ( gr_screen.max_w*(100-fi) )/200;
2798 yborder = ( gr_screen.max_h*(100-fi) )/200;
2800 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2806 void show_debug_stuff()
2809 int laser_count = 0, missile_count = 0;
2811 for (i=0; i<MAX_OBJECTS; i++) {
2812 if (Objects[i].type == OBJ_WEAPON){
2813 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2815 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2821 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2824 extern int Tool_enabled;
2829 int tst_bitmap = -1;
2831 float tst_offset, tst_offset_total;
2834 void game_tst_frame_pre()
2842 g3_rotate_vertex(&v, &tst_pos);
2843 g3_project_vertex(&v);
2846 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2850 // big ship? always tst
2852 // within 3000 meters
2853 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2857 // within 300 meters
2858 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2865 void game_tst_frame()
2875 tst_time = time(NULL);
2877 // load the tst bitmap
2878 switch((int)frand_range(0.0f, 3.0)){
2880 tst_bitmap = bm_load("ig_jim");
2882 mprintf(("TST 0\n"));
2886 tst_bitmap = bm_load("ig_kan");
2888 mprintf(("TST 1\n"));
2892 tst_bitmap = bm_load("ig_jim");
2894 mprintf(("TST 2\n"));
2898 tst_bitmap = bm_load("ig_kan");
2900 mprintf(("TST 3\n"));
2909 // get the tst bitmap dimensions
2911 bm_get_info(tst_bitmap, &w, &h);
2914 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2916 snd_play(&Snds[SND_VASUDAN_BUP]);
2918 // tst x and direction
2922 tst_offset_total = (float)w;
2923 tst_offset = (float)w;
2925 tst_x = (float)gr_screen.max_w;
2926 tst_offset_total = (float)-w;
2927 tst_offset = (float)w;
2935 float diff = (tst_offset_total / 0.5f) * flFrametime;
2941 tst_offset -= fl_abs(diff);
2942 } else if(tst_mode == 2){
2945 tst_offset -= fl_abs(diff);
2949 gr_set_bitmap(tst_bitmap);
2950 gr_bitmap((int)tst_x, (int)tst_y);
2953 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2957 // if we passed the switch point
2958 if(tst_offset <= 0.0f){
2963 tst_stamp = timestamp(1000);
2964 tst_offset = fl_abs(tst_offset_total);
2975 void game_tst_mark(object *objp, ship *shipp)
2984 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2987 sip = &Ship_info[shipp->ship_info_index];
2994 tst_pos = objp->pos;
2995 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3001 extern void render_shields();
3003 void player_repair_frame(float frametime)
3005 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3007 for(idx=0;idx<MAX_PLAYERS;idx++){
3010 np = &Net_players[idx];
3012 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)){
3014 // don't rearm/repair if the player is dead or dying/departing
3015 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3016 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3021 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3022 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3028 #define NUM_FRAMES_TEST 300
3029 #define NUM_MIXED_SOUNDS 16
3030 void do_timing_test(float flFrametime)
3032 static int framecount = 0;
3033 static int test_running = 0;
3034 static float test_time = 0.0f;
3036 static int snds[NUM_MIXED_SOUNDS];
3039 if ( test_running ) {
3041 test_time += flFrametime;
3042 if ( framecount >= NUM_FRAMES_TEST ) {
3044 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3045 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3050 if ( Test_begin == 1 ) {
3056 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3059 // start looping digital sounds
3060 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3061 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3068 DCF(dcf_fov, "Change the field of view")
3071 dc_get_arg(ARG_FLOAT|ARG_NONE);
3072 if ( Dc_arg_type & ARG_NONE ) {
3073 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3074 dc_printf( "Zoom factor reset\n" );
3076 if ( Dc_arg_type & ARG_FLOAT ) {
3077 if (Dc_arg_float < 0.25f) {
3078 Viewer_zoom = 0.25f;
3079 dc_printf("Zoom factor pinned at 0.25.\n");
3080 } else if (Dc_arg_float > 1.25f) {
3081 Viewer_zoom = 1.25f;
3082 dc_printf("Zoom factor pinned at 1.25.\n");
3084 Viewer_zoom = Dc_arg_float;
3090 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3093 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3097 DCF(framerate_cap, "Sets the framerate cap")
3100 dc_get_arg(ARG_INT);
3101 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3102 Framerate_cap = Dc_arg_int;
3104 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3110 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3111 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3112 dc_printf("[n] must be from 1 to 120.\n");
3116 if ( Framerate_cap )
3117 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3119 dc_printf("There is no framerate cap currently active.\n");
3123 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3124 int Show_viewing_from_self = 0;
3126 void say_view_target()
3128 object *view_target;
3130 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3131 view_target = &Objects[Player_ai->target_objnum];
3133 view_target = Player_obj;
3135 if (Game_mode & GM_DEAD) {
3136 if (Player_ai->target_objnum != -1)
3137 view_target = &Objects[Player_ai->target_objnum];
3140 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3141 if (view_target != Player_obj){
3143 char *view_target_name = NULL;
3144 switch(Objects[Player_ai->target_objnum].type) {
3146 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3149 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3150 Viewer_mode &= ~VM_OTHER_SHIP;
3152 case OBJ_JUMP_NODE: {
3153 char jump_node_name[128];
3154 strcpy(jump_node_name, XSTR( "jump node", 184));
3155 view_target_name = jump_node_name;
3156 Viewer_mode &= ~VM_OTHER_SHIP;
3165 if ( view_target_name ) {
3166 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3167 Show_viewing_from_self = 1;
3170 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3171 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3172 Show_viewing_from_self = 1;
3174 if (Show_viewing_from_self)
3175 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3180 Last_view_target = view_target;
3184 float Game_hit_x = 0.0f;
3185 float Game_hit_y = 0.0f;
3187 // Reset at the beginning of each frame
3188 void game_whack_reset()
3194 // Apply a 2d whack to the player
3195 void game_whack_apply( float x, float y )
3197 // Do some force feedback
3198 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3204 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3207 // call to apply a "shudder"
3208 void game_shudder_apply(int time, float intensity)
3210 Game_shudder_time = timestamp(time);
3211 Game_shudder_total = time;
3212 Game_shudder_intensity = intensity;
3215 #define FF_SCALE 10000
3216 void apply_hud_shake(matrix *eye_orient)
3218 if (Viewer_obj == Player_obj) {
3219 physics_info *pi = &Player_obj->phys_info;
3227 // Make eye shake due to afterburner
3228 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3231 dtime = timestamp_until(pi->afterburner_decay);
3235 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3236 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3239 // Make eye shake due to engine wash
3241 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3244 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3245 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3247 // get the intensity
3248 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3252 vm_vec_rand_vec_quick(&rand_vec);
3255 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3259 // make hud shake due to shuddering
3260 if(Game_shudder_time != -1){
3261 // if the timestamp has elapsed
3262 if(timestamp_elapsed(Game_shudder_time)){
3263 Game_shudder_time = -1;
3265 // otherwise apply some shudder
3269 dtime = timestamp_until(Game_shudder_time);
3273 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));
3274 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));
3279 vm_angles_2_matrix(&tm, &tangles);
3280 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3281 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3282 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3283 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3288 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3290 // Player's velocity just before he blew up. Used to keep camera target moving.
3291 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3293 // Set eye_pos and eye_orient based on view mode.
3294 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3298 static int last_Viewer_mode = 0;
3299 static int last_Game_mode = 0;
3300 static int last_Viewer_objnum = -1;
3302 // This code is supposed to detect camera "cuts"... like going between
3305 // determine if we need to regenerate the nebula
3306 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3307 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3308 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3309 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3310 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3311 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3312 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3313 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3314 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3317 // regenerate the nebula
3321 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3322 //mprintf(( "************** Camera cut! ************\n" ));
3323 last_Viewer_mode = Viewer_mode;
3324 last_Game_mode = Game_mode;
3326 // Camera moved. Tell stars & debris to not do blurring.
3332 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3333 player_display_packlock_view();
3336 game_set_view_clip();
3338 if (Game_mode & GM_DEAD) {
3339 vector vec_to_deader, view_pos;
3342 Viewer_mode |= VM_DEAD_VIEW;
3344 if (Player_ai->target_objnum != -1) {
3345 int view_from_player = 1;
3347 if (Viewer_mode & VM_OTHER_SHIP) {
3348 // View from target.
3349 Viewer_obj = &Objects[Player_ai->target_objnum];
3351 last_Viewer_objnum = Player_ai->target_objnum;
3353 if ( Viewer_obj->type == OBJ_SHIP ) {
3354 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3355 view_from_player = 0;
3358 last_Viewer_objnum = -1;
3361 if ( view_from_player ) {
3362 // View target from player ship.
3364 *eye_pos = Player_obj->pos;
3365 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3366 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3369 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3371 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3372 dist += flFrametime * 16.0f;
3374 vm_vec_scale(&vec_to_deader, -dist);
3375 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3377 view_pos = Player_obj->pos;
3379 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3380 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3381 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3382 Dead_player_last_vel = Player_obj->phys_info.vel;
3383 //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));
3384 } else if (Player_ai->target_objnum != -1) {
3385 view_pos = Objects[Player_ai->target_objnum].pos;
3387 // Make camera follow explosion, but gradually slow down.
3388 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3389 view_pos = Player_obj->pos;
3390 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3391 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3394 *eye_pos = Dead_camera_pos;
3396 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3398 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3403 // if supernova shockwave
3404 if(supernova_camera_cut()){
3408 // call it dead view
3409 Viewer_mode |= VM_DEAD_VIEW;
3411 // set eye pos and orient
3412 supernova_set_view(eye_pos, eye_orient);
3414 // If already blown up, these other modes can override.
3415 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3416 Viewer_mode &= ~VM_DEAD_VIEW;
3418 Viewer_obj = Player_obj;
3420 if (Viewer_mode & VM_OTHER_SHIP) {
3421 if (Player_ai->target_objnum != -1){
3422 Viewer_obj = &Objects[Player_ai->target_objnum];
3423 last_Viewer_objnum = Player_ai->target_objnum;
3425 Viewer_mode &= ~VM_OTHER_SHIP;
3426 last_Viewer_objnum = -1;
3429 last_Viewer_objnum = -1;
3432 if (Viewer_mode & VM_EXTERNAL) {
3435 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3436 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3438 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3440 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3441 vm_vec_normalize(&eye_dir);
3442 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3445 // Modify the orientation based on head orientation.
3446 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3448 } else if ( Viewer_mode & VM_CHASE ) {
3451 if ( Viewer_obj->phys_info.speed < 0.1 )
3452 move_dir = Viewer_obj->orient.fvec;
3454 move_dir = Viewer_obj->phys_info.vel;
3455 vm_vec_normalize(&move_dir);
3458 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3459 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3460 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3461 vm_vec_normalize(&eye_dir);
3463 // JAS: I added the following code because if you slew up using
3464 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3465 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3466 // call because the up and the forward vector are the same. I fixed
3467 // it by adding in a fraction of the right vector all the time to the
3469 vector tmp_up = Viewer_obj->orient.uvec;
3470 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3472 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3475 // Modify the orientation based on head orientation.
3476 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3477 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3478 *eye_pos = Camera_pos;
3480 ship * shipp = &Ships[Player_obj->instance];
3482 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3483 vm_vec_normalize(&eye_dir);
3484 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3487 // get an eye position based upon the correct type of object
3488 switch(Viewer_obj->type){
3490 // make a call to get the eye point for the player object
3491 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3494 // make a call to get the eye point for the player object
3495 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3501 #ifdef JOHNS_DEBUG_CODE
3502 john_debug_stuff(&eye_pos, &eye_orient);
3508 apply_hud_shake(eye_orient);
3510 // setup neb2 rendering
3511 neb2_render_setup(eye_pos, eye_orient);
3515 extern void ai_debug_render_stuff();
3518 int Game_subspace_effect = 0;
3519 DCF_BOOL( subspace, Game_subspace_effect );
3521 // Does everything needed to render a frame
3522 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3526 g3_start_frame(game_zbuffer);
3527 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3529 // maybe offset the HUD (jitter stuff)
3530 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3531 HUD_set_offsets(Viewer_obj, !dont_offset);
3533 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3534 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3535 // must be done before ships are rendered
3536 if ( MULTIPLAYER_CLIENT ) {
3537 shield_point_multi_setup();
3540 if ( Game_subspace_effect ) {
3541 stars_draw(0,0,0,1);
3543 stars_draw(1,1,1,0);
3546 obj_render_all(obj_render);
3547 beam_render_all(); // render all beam weapons
3548 particle_render_all(); // render particles after everything else.
3549 trail_render_all(); // render missilie trails after everything else.
3550 mflash_render_all(); // render all muzzle flashes
3552 // Why do we not show the shield effect in these modes? Seems ok.
3553 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3557 // render nebula lightning
3560 // render local player nebula
3561 neb2_render_player();
3564 ai_debug_render_stuff();
3567 #ifndef RELEASE_REAL
3568 // game_framerate_check();
3572 extern void snd_spew_debug_info();
3573 snd_spew_debug_info();
3576 //================ END OF 3D RENDERING STUFF ====================
3580 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3581 hud_maybe_clear_head_area();
3582 anim_render_all(0, flFrametime);
3585 extern int Multi_display_netinfo;
3586 if(Multi_display_netinfo){
3587 extern void multi_display_netinfo();
3588 multi_display_netinfo();
3591 game_tst_frame_pre();
3594 do_timing_test(flFrametime);
3598 extern int OO_update_index;
3599 multi_rate_display(OO_update_index, 375, 0);
3604 extern void oo_display();
3611 //#define JOHNS_DEBUG_CODE 1
3613 #ifdef JOHNS_DEBUG_CODE
3614 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3616 //if ( keyd_pressed[KEY_LSHIFT] )
3618 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3620 model_subsystem *turret = tsys->system_info;
3622 if (turret->type == SUBSYSTEM_TURRET ) {
3624 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3626 ship_model_start(tobj);
3628 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3629 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3630 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3632 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3634 ship_model_stop(tobj);
3644 // following function for dumping frames for purposes of building trailers.
3647 // function to toggle state of dumping every frame into PCX when playing the game
3648 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3652 if ( Debug_dump_frames == 0 ) {
3654 Debug_dump_frames = 15;
3655 Debug_dump_trigger = 0;
3656 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3657 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3660 Debug_dump_frames = 0;
3661 Debug_dump_trigger = 0;
3662 gr_dump_frame_stop();
3663 dc_printf( "Frame dumping is now OFF\n" );
3669 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3673 if ( Debug_dump_frames == 0 ) {
3675 Debug_dump_frames = 15;
3676 Debug_dump_trigger = 1;
3677 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3678 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3681 Debug_dump_frames = 0;
3682 Debug_dump_trigger = 0;
3683 gr_dump_frame_stop();
3684 dc_printf( "Frame dumping is now OFF\n" );
3690 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3694 if ( Debug_dump_frames == 0 ) {
3696 Debug_dump_frames = 30;
3697 Debug_dump_trigger = 0;
3698 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3699 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3702 Debug_dump_frames = 0;
3703 Debug_dump_trigger = 0;
3704 gr_dump_frame_stop();
3705 dc_printf( "Frame dumping is now OFF\n" );
3711 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3715 if ( Debug_dump_frames == 0 ) {
3717 Debug_dump_frames = 30;
3718 Debug_dump_trigger = 1;
3719 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3720 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3723 Debug_dump_frames = 0;
3724 Debug_dump_trigger = 0;
3725 gr_dump_frame_stop();
3726 dc_printf( "Triggered frame dumping is now OFF\n" );
3732 void game_maybe_dump_frame()
3734 if ( !Debug_dump_frames ){
3738 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3745 Debug_dump_frame_num++;
3751 extern int Player_dead_state;
3753 // Flip the page and time how long it took.
3754 void game_flip_page_and_time_it()
3758 t1 = timer_get_fixed_seconds();
3760 t2 = timer_get_fixed_seconds();
3762 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3763 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3766 void game_simulation_frame()
3768 // blow ships up in multiplayer dogfight
3769 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){
3770 // blow up all non-player ships
3771 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3774 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3776 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)){
3777 moveup = GET_NEXT(moveup);
3780 shipp = &Ships[Objects[moveup->objnum].instance];
3781 sip = &Ship_info[shipp->ship_info_index];
3783 // only blow up small ships
3784 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3785 // function to simply explode a ship where it is currently at
3786 ship_self_destruct( &Objects[moveup->objnum] );
3789 moveup = GET_NEXT(moveup);
3795 // process AWACS stuff - do this first thing
3798 // single player, set Player hits_this_frame to 0
3799 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3800 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3801 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3805 supernova_process();
3806 if(supernova_active() >= 5){
3810 // fire targeting lasers now so that
3811 // 1 - created this frame
3812 // 2 - collide this frame
3813 // 3 - render this frame
3814 // 4 - ignored and deleted next frame
3815 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3817 ship_process_targeting_lasers();
3819 // do this here so that it works for multiplayer
3821 // get viewer direction
3822 int viewer_direction = PHYSICS_VIEWER_REAR;
3824 if(Viewer_mode == 0){
3825 viewer_direction = PHYSICS_VIEWER_FRONT;
3827 if(Viewer_mode & VM_PADLOCK_UP){
3828 viewer_direction = PHYSICS_VIEWER_UP;
3830 else if(Viewer_mode & VM_PADLOCK_REAR){
3831 viewer_direction = PHYSICS_VIEWER_REAR;
3833 else if(Viewer_mode & VM_PADLOCK_LEFT){
3834 viewer_direction = PHYSICS_VIEWER_LEFT;
3836 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3837 viewer_direction = PHYSICS_VIEWER_RIGHT;
3840 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3842 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3845 #define VM_PADLOCK_UP (1 << 7)
3846 #define VM_PADLOCK_REAR (1 << 8)
3847 #define VM_PADLOCK_LEFT (1 << 9)
3848 #define VM_PADLOCK_RIGHT (1 << 10)
3850 // evaluate mission departures and arrivals before we process all objects.
3851 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3853 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3854 // ships/wing packets.
3855 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3856 mission_parse_eval_stuff();
3859 // if we're an observer, move ourselves seperately from the standard physics
3860 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3861 obj_observer_move(flFrametime);
3864 // move all the objects now
3865 obj_move_all(flFrametime);
3867 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3868 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3869 // ship_check_cargo_all();
3870 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3871 mission_eval_goals();
3875 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3876 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3877 training_check_objectives();
3880 // do all interpolation now
3881 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3882 // client side processing of warping in effect stages
3883 multi_do_client_warp(flFrametime);
3885 // client side movement of an observer
3886 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3887 obj_observer_move(flFrametime);
3890 // move all objects - does interpolation now as well
3891 obj_move_all(flFrametime);
3894 // only process the message queue when the player is "in" the game
3895 if ( !Pre_player_entry ){
3896 message_queue_process(); // process any messages send to the player
3899 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3900 message_maybe_distort(); // maybe distort incoming message if comms damaged
3901 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3902 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3903 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3906 if(!(Game_mode & GM_STANDALONE_SERVER)){
3907 // process some stuff every frame (before frame is rendered)
3908 emp_process_local();
3910 hud_update_frame(); // update hud systems
3912 if (!physics_paused) {
3913 // Move particle system
3914 particle_move_all(flFrametime);
3916 // Move missile trails
3917 trail_move_all(flFrametime);
3919 // process muzzle flashes
3920 mflash_process_all();
3922 // Flash the gun flashes
3923 shipfx_flash_do_frame(flFrametime);
3925 shockwave_move_all(flFrametime); // update all the shockwaves
3928 // subspace missile strikes
3931 obj_snd_do_frame(); // update the object-linked persistant sounds
3932 game_maybe_update_sound_environment();
3933 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3935 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3937 if ( Game_subspace_effect ) {
3938 game_start_subspace_ambient_sound();
3944 // Maybe render and process the dead-popup
3945 void game_maybe_do_dead_popup(float frametime)
3947 if ( popupdead_is_active() ) {
3949 int choice = popupdead_do_frame(frametime);
3951 if ( Game_mode & GM_NORMAL ) {
3955 if(game_do_cd_mission_check(Game_current_mission_filename)){
3956 gameseq_post_event(GS_EVENT_ENTER_GAME);
3958 gameseq_post_event(GS_EVENT_MAIN_MENU);
3963 gameseq_post_event(GS_EVENT_END_GAME);
3968 if(game_do_cd_mission_check(Game_current_mission_filename)){
3969 gameseq_post_event(GS_EVENT_START_GAME);
3971 gameseq_post_event(GS_EVENT_MAIN_MENU);
3975 // this should only happen during a red alert mission
3978 Assert(The_mission.red_alert);
3979 if(!The_mission.red_alert){
3981 if(game_do_cd_mission_check(Game_current_mission_filename)){
3982 gameseq_post_event(GS_EVENT_START_GAME);
3984 gameseq_post_event(GS_EVENT_MAIN_MENU);
3989 // choose the previous mission
3990 mission_campaign_previous_mission();
3992 if(game_do_cd_mission_check(Game_current_mission_filename)){
3993 gameseq_post_event(GS_EVENT_START_GAME);
3995 gameseq_post_event(GS_EVENT_MAIN_MENU);
4006 case POPUPDEAD_DO_MAIN_HALL:
4007 multi_quit_game(PROMPT_NONE,-1);
4010 case POPUPDEAD_DO_RESPAWN:
4011 multi_respawn_normal();
4012 event_music_player_respawn();
4015 case POPUPDEAD_DO_OBSERVER:
4016 multi_respawn_observer();
4017 event_music_player_respawn_as_observer();
4026 if ( leave_popup ) {
4032 // returns true if player is actually in a game_play stats
4033 int game_actually_playing()
4037 state = gameseq_get_state();
4038 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4044 // Draw the 2D HUD gauges
4045 void game_render_hud_2d()
4047 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4051 HUD_render_2d(flFrametime);
4055 // Draw the 3D-dependant HUD gauges
4056 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4058 g3_start_frame(0); // 0 = turn zbuffering off
4059 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4061 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4062 HUD_render_3d(flFrametime);
4066 game_sunspot_process(flFrametime);
4068 // Diminish the palette effect
4069 game_flash_diminish(flFrametime);
4077 int actually_playing;
4078 fix total_time1, total_time2;
4079 fix render2_time1=0, render2_time2=0;
4080 fix render3_time1=0, render3_time2=0;
4081 fix flip_time1=0, flip_time2=0;
4082 fix clear_time1=0, clear_time2=0;
4088 if (Framerate_delay) {
4089 int start_time = timer_get_milliseconds();
4090 while (timer_get_milliseconds() < start_time + Framerate_delay)
4096 demo_do_frame_start();
4098 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4103 // start timing frame
4104 timing_frame_start();
4106 total_time1 = timer_get_fixed_seconds();
4108 // var to hold which state we are in
4109 actually_playing = game_actually_playing();
4111 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4112 if (!(Game_mode & GM_STANDALONE_SERVER)){
4113 Assert( OBJ_INDEX(Player_obj) >= 0 );
4117 if (Missiontime > Entry_delay_time){
4118 Pre_player_entry = 0;
4120 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4123 // Note: These are done even before the player enters, else buffers can overflow.
4124 if (! (Game_mode & GM_STANDALONE_SERVER)){
4128 shield_frame_init();
4130 if ( Player->control_mode != PCM_NORMAL )
4133 if ( !Pre_player_entry && actually_playing ) {
4134 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4136 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4137 game_process_keys();
4139 // don't read flying controls if we're playing a demo back
4140 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4141 read_player_controls( Player_obj, flFrametime);
4145 // if we're not the master, we may have to send the server-critical ship status button_info bits
4146 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4147 multi_maybe_send_ship_status();
4152 // Reset the whack stuff
4155 // These two lines must be outside of Pre_player_entry code,
4156 // otherwise too many lights are added.
4159 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4163 game_simulation_frame();
4165 // if not actually in a game play state, then return. This condition could only be true in
4166 // a multiplayer game.
4167 if ( !actually_playing ) {
4168 Assert( Game_mode & GM_MULTIPLAYER );
4172 if (!Pre_player_entry) {
4173 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4174 clear_time1 = timer_get_fixed_seconds();
4175 // clear the screen to black
4177 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4181 clear_time2 = timer_get_fixed_seconds();
4182 render3_time1 = timer_get_fixed_seconds();
4183 game_render_frame_setup(&eye_pos, &eye_orient);
4184 game_render_frame( &eye_pos, &eye_orient );
4186 // save the eye position and orientation
4187 if ( Game_mode & GM_MULTIPLAYER ) {
4188 Net_player->s_info.eye_pos = eye_pos;
4189 Net_player->s_info.eye_orient = eye_orient;
4192 hud_show_target_model();
4194 // check to see if we should display the death died popup
4195 if(Game_mode & GM_DEAD_BLEW_UP){
4196 if(Game_mode & GM_MULTIPLAYER){
4197 // catch the situation where we're supposed to be warping out on this transition
4198 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4199 gameseq_post_event(GS_EVENT_DEBRIEF);
4200 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4201 Player_died_popup_wait = -1;
4205 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4206 Player_died_popup_wait = -1;
4212 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4213 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4214 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4215 if(!popupdead_is_active()){
4219 Player_multi_died_check = -1;
4223 render3_time2 = timer_get_fixed_seconds();
4224 render2_time1 = timer_get_fixed_seconds();
4227 game_get_framerate();
4228 game_show_framerate();
4230 game_show_time_left();
4232 // Draw the 2D HUD gauges
4233 if(supernova_active() < 3){
4234 game_render_hud_2d();
4237 game_set_view_clip();
4239 // Draw 3D HUD gauges
4240 game_render_hud_3d(&eye_pos, &eye_orient);
4244 render2_time2 = timer_get_fixed_seconds();
4246 // maybe render and process the dead popup
4247 game_maybe_do_dead_popup(flFrametime);
4249 // start timing frame
4250 timing_frame_stop();
4251 // timing_display(30, 10);
4253 // If a regular popup is active, don't flip (popup code flips)
4254 if( !popup_running_state() ){
4255 flip_time1 = timer_get_fixed_seconds();
4256 game_flip_page_and_time_it();
4257 flip_time2 = timer_get_fixed_seconds();
4261 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4264 game_show_standalone_framerate();
4268 game_do_training_checks();
4271 // process lightning (nebula only)
4274 total_time2 = timer_get_fixed_seconds();
4276 // Got some timing numbers
4277 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4278 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4279 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4280 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4281 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4284 demo_do_frame_end();
4286 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4292 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4293 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4294 // died. This resulted in screwed up death sequences.
4296 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4297 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4298 static int timer_paused=0;
4299 static int stop_count,start_count;
4300 static int time_stopped,time_started;
4301 int saved_timestamp_ticker = -1;
4303 void game_reset_time()
4305 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4309 // Last_time = timer_get_fixed_seconds();
4315 void game_stop_time()
4317 if (timer_paused==0) {
4319 time = timer_get_fixed_seconds();
4320 // Save how much time progressed so far in the frame so we can
4321 // use it when we unpause.
4322 Last_delta_time = time - Last_time;
4324 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4325 if (Last_delta_time < 0) {
4326 #if defined(TIMER_TEST) && !defined(NDEBUG)
4327 Int3(); //get Matt!!!!
4329 Last_delta_time = 0;
4331 #if defined(TIMER_TEST) && !defined(NDEBUG)
4332 time_stopped = time;
4335 // Stop the timer_tick stuff...
4336 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4337 saved_timestamp_ticker = timestamp_ticker;
4341 #if defined(TIMER_TEST) && !defined(NDEBUG)
4346 void game_start_time()
4349 Assert(timer_paused >= 0);
4350 if (timer_paused==0) {
4352 time = timer_get_fixed_seconds();
4353 #if defined(TIMER_TEST) && !defined(NDEBUG)
4355 Int3(); //get Matt!!!!
4358 // Take current time, and set it backwards to account for time
4359 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4360 // will be correct when it goes to calculate the frametime next
4362 Last_time = time - Last_delta_time;
4363 #if defined(TIMER_TEST) && !defined(NDEBUG)
4364 time_started = time;
4367 // Restore the timer_tick stuff...
4368 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4369 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4370 timestamp_ticker = saved_timestamp_ticker;
4371 saved_timestamp_ticker = -1;
4374 #if defined(TIMER_TEST) && !defined(NDEBUG)
4380 void game_set_frametime(int state)
4383 float frame_cap_diff;
4385 thistime = timer_get_fixed_seconds();
4387 if ( Last_time == 0 )
4388 Frametime = F1_0 / 30;
4390 Frametime = thistime - Last_time;
4392 // Frametime = F1_0 / 30;
4394 fix debug_frametime = Frametime; // Just used to display frametime.
4396 // If player hasn't entered mission yet, make frame take 1/4 second.
4397 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4400 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4402 fix frame_speed = F1_0 / Debug_dump_frames;
4404 if (Frametime > frame_speed ){
4405 nprintf(("warning","slow frame: %x\n",Frametime));
4408 thistime = timer_get_fixed_seconds();
4409 Frametime = thistime - Last_time;
4410 } while (Frametime < frame_speed );
4412 Frametime = frame_speed;
4416 Assert( Framerate_cap > 0 );
4418 // Cap the framerate so it doesn't get too high.
4422 cap = F1_0/Framerate_cap;
4423 if (Frametime < cap) {
4424 thistime = cap - Frametime;
4425 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4426 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4428 thistime = timer_get_fixed_seconds();
4432 if((Game_mode & GM_STANDALONE_SERVER) &&
4433 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4435 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4436 Sleep((DWORD)(frame_cap_diff*1000));
4438 thistime += fl2f((frame_cap_diff));
4440 Frametime = thistime - Last_time;
4443 // If framerate is too low, cap it.
4444 if (Frametime > MAX_FRAMETIME) {
4446 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4448 // to remove warnings in release build
4449 debug_frametime = fl2f(flFrametime);
4451 Frametime = MAX_FRAMETIME;
4454 Frametime = fixmul(Frametime, Game_time_compression);
4456 Last_time = thistime;
4457 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4459 flFrametime = f2fl(Frametime);
4460 //if(!(Game_mode & GM_PLAYING_DEMO)){
4461 timestamp_inc(flFrametime);
4463 /* if ((Framecount > 0) && (Framecount < 10)) {
4464 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4469 // This is called from game_do_frame(), and from navmap_do_frame()
4470 void game_update_missiontime()
4472 // TODO JAS: Put in if and move this into game_set_frametime,
4473 // fix navmap to call game_stop/start_time
4474 //if ( !timer_paused )
4475 Missiontime += Frametime;
4478 void game_do_frame()
4480 game_set_frametime(GS_STATE_GAME_PLAY);
4481 game_update_missiontime();
4483 if (Game_mode & GM_STANDALONE_SERVER) {
4484 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4487 if ( game_single_step && (last_single_step == game_single_step) ) {
4488 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4489 while( key_checkch() == 0 )
4491 os_set_title( XSTR( "FreeSpace", 171) );
4492 Last_time = timer_get_fixed_seconds();
4495 last_single_step = game_single_step;
4497 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4498 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4502 Keep_mouse_centered = 0;
4503 monitor_update(); // Update monitor variables
4506 void multi_maybe_do_frame()
4508 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4513 int Joymouse_button_status = 0;
4515 // Flush all input devices
4523 Joymouse_button_status = 0;
4525 //mprintf(("Game flush!\n" ));
4528 // function for multiplayer only which calls game_do_state_common() when running the
4530 void game_do_dc_networking()
4532 Assert( Game_mode & GM_MULTIPLAYER );
4534 game_do_state_common( gameseq_get_state() );
4537 // Call this whenever in a loop, or when you need to check for a keystroke.
4538 int game_check_key()
4544 // convert keypad enter to normal enter
4545 if ((k & KEY_MASK) == KEY_PADENTER)
4546 k = (k & ~KEY_MASK) | KEY_ENTER;
4553 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4554 static int Demo_show_trailer_timestamp = 0;
4556 void demo_reset_trailer_timer()
4558 Demo_show_trailer_timestamp = timer_get_milliseconds();
4561 void demo_maybe_show_trailer(int k)
4564 // if key pressed, reset demo trailer timer
4566 demo_reset_trailer_timer();
4570 // if mouse moved, reset demo trailer timer
4573 mouse_get_delta(&dx, &dy);
4574 if ( (dx > 0) || (dy > 0) ) {
4575 demo_reset_trailer_timer();
4579 // if joystick has moved, reset demo trailer timer
4582 joy_get_delta(&dx, &dy);
4583 if ( (dx > 0) || (dy > 0) ) {
4584 demo_reset_trailer_timer();
4588 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4589 // the low-level code. Ugly, I know... but was the simplest and most
4592 // if 30 seconds since last demo trailer time reset, launch movie
4593 if ( os_foreground() ) {
4594 int now = timer_get_milliseconds();
4595 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4596 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4598 movie_play( NOX("fstrailer2.mve") );
4599 demo_reset_trailer_timer();
4607 // same as game_check_key(), except this is used while actually in the game. Since there
4608 // generally are differences between game control keys and general UI keys, makes sense to
4609 // have seperate functions for each case. If you are not checking a game control while in a
4610 // mission, you should probably be using game_check_key() instead.
4615 if (!os_foreground()) {
4620 // If we're in a single player game, pause it.
4621 if (!(Game_mode & GM_MULTIPLAYER)){
4622 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4623 game_process_pause_key();
4631 demo_maybe_show_trailer(k);
4634 // Move the mouse cursor with the joystick.
4635 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4636 // Move the mouse cursor with the joystick
4640 joy_get_pos( &jx, &jy, &jz, &jr );
4642 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4643 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4646 mouse_get_real_pos( &mx, &my );
4647 mouse_set_pos( mx+dx, my+dy );
4652 m = mouse_down(MOUSE_LEFT_BUTTON);
4654 if ( j != Joymouse_button_status ) {
4655 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4656 Joymouse_button_status = j;
4658 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4659 } else if ( (!j) && (m) ) {
4660 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4665 // if we should be ignoring keys because of some multiplayer situations
4666 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4670 // If a popup is running, don't process all the Fn keys
4671 if( popup_active() ) {
4675 state = gameseq_get_state();
4677 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4680 case KEY_DEBUGGED + KEY_BACKSP:
4685 launch_context_help();
4690 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4692 // don't allow f2 while warping out in multiplayer
4693 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4698 case GS_STATE_INITIAL_PLAYER_SELECT:
4699 case GS_STATE_OPTIONS_MENU:
4700 case GS_STATE_HUD_CONFIG:
4701 case GS_STATE_CONTROL_CONFIG:
4702 case GS_STATE_DEATH_DIED:
4703 case GS_STATE_DEATH_BLEW_UP:
4704 case GS_STATE_VIEW_MEDALS:
4708 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4715 // hotkey selection screen -- only valid from briefing and beyond.
4718 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) ) {
4719 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4725 case KEY_DEBUGGED + KEY_F3:
4726 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4729 case KEY_DEBUGGED + KEY_F4:
4730 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4734 if(Game_mode & GM_MULTIPLAYER){
4735 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4736 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4740 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4741 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4747 case KEY_ESC | KEY_SHIFTED:
4748 // make sure to quit properly out of multiplayer
4749 if(Game_mode & GM_MULTIPLAYER){
4750 multi_quit_game(PROMPT_NONE);
4753 gameseq_post_event( GS_EVENT_QUIT_GAME );
4758 case KEY_DEBUGGED + KEY_P:
4761 case KEY_PRINT_SCRN:
4763 static int counter = 0;
4768 sprintf( tmp_name, NOX("screen%02d"), counter );
4770 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4771 gr_print_screen(tmp_name);
4779 case KEY_SHIFTED | KEY_ENTER: {
4781 #if !defined(NDEBUG)
4783 if ( Game_mode & GM_NORMAL ){
4787 // if we're in multiplayer mode, do some special networking
4788 if(Game_mode & GM_MULTIPLAYER){
4789 debug_console(game_do_dc_networking);
4796 if ( Game_mode & GM_NORMAL )
4810 gameseq_post_event(GS_EVENT_QUIT_GAME);
4813 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4816 void camera_set_position( vector *pos )
4821 void camera_set_orient( matrix *orient )
4823 Camera_orient = *orient;
4826 void camera_set_velocity( vector *vel, int instantaneous )
4828 Camera_desired_velocity.x = 0.0f;
4829 Camera_desired_velocity.y = 0.0f;
4830 Camera_desired_velocity.z = 0.0f;
4832 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4833 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4834 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4836 if ( instantaneous ) {
4837 Camera_velocity = Camera_desired_velocity;
4845 vector new_vel, delta_pos;
4847 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4848 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4849 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4851 Camera_velocity = new_vel;
4853 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4855 vm_vec_add2( &Camera_pos, &delta_pos );
4857 float ot = Camera_time+0.0f;
4859 Camera_time += flFrametime;
4861 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4864 tmp.z = 4.739f; // always go this fast forward.
4866 // pick x and y velocities so they are always on a
4867 // circle with a 25 m radius.
4869 float tmp_angle = frand()*PI2;
4871 tmp.x = 22.0f * (float)sin(tmp_angle);
4872 tmp.y = -22.0f * (float)cos(tmp_angle);
4874 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4876 //mprintf(( "Changing velocity!\n" ));
4877 camera_set_velocity( &tmp, 0 );
4880 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4881 vector tmp = { 0.0f, 0.0f, 0.0f };
4882 camera_set_velocity( &tmp, 0 );
4887 void end_demo_campaign_do()
4889 #if defined(FS2_DEMO)
4890 // show upsell screens
4891 demo_upsell_show_screens();
4892 #elif defined(OEM_BUILD)
4893 // show oem upsell screens
4894 oem_upsell_show_screens();
4897 // drop into main hall
4898 gameseq_post_event( GS_EVENT_MAIN_MENU );
4901 // All code to process events. This is the only place
4902 // that you should change the state of the game.
4903 void game_process_event( int current_state, int event )
4905 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4908 case GS_EVENT_SIMULATOR_ROOM:
4909 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4912 case GS_EVENT_MAIN_MENU:
4913 gameseq_set_state(GS_STATE_MAIN_MENU);
4916 case GS_EVENT_OPTIONS_MENU:
4917 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4920 case GS_EVENT_BARRACKS_MENU:
4921 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4924 case GS_EVENT_TECH_MENU:
4925 gameseq_set_state(GS_STATE_TECH_MENU);
4928 case GS_EVENT_TRAINING_MENU:
4929 gameseq_set_state(GS_STATE_TRAINING_MENU);
4932 case GS_EVENT_START_GAME:
4933 Select_default_ship = 0;
4934 Player_multi_died_check = -1;
4935 gameseq_set_state(GS_STATE_CMD_BRIEF);
4938 case GS_EVENT_START_BRIEFING:
4939 gameseq_set_state(GS_STATE_BRIEFING);
4942 case GS_EVENT_DEBRIEF:
4943 // did we end the campaign in the main freespace 2 single player campaign?
4944 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4945 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4947 gameseq_set_state(GS_STATE_DEBRIEF);
4950 Player_multi_died_check = -1;
4953 case GS_EVENT_SHIP_SELECTION:
4954 gameseq_set_state( GS_STATE_SHIP_SELECT );
4957 case GS_EVENT_WEAPON_SELECTION:
4958 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4961 case GS_EVENT_ENTER_GAME:
4963 // maybe start recording a demo
4965 demo_start_record("test.fsd");
4969 if (Game_mode & GM_MULTIPLAYER) {
4970 // if we're respawning, make sure we change the view mode so that the hud shows up
4971 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4975 gameseq_set_state(GS_STATE_GAME_PLAY);
4977 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4980 Player_multi_died_check = -1;
4982 // clear multiplayer button info
4983 extern button_info Multi_ship_status_bi;
4984 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4986 Start_time = f2fl(timer_get_approx_seconds());
4988 mprintf(("Entering game at time = %7.3f\n", Start_time));
4992 case GS_EVENT_START_GAME_QUICK:
4993 Select_default_ship = 1;
4994 gameseq_post_event(GS_EVENT_ENTER_GAME);
4998 case GS_EVENT_END_GAME:
4999 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5000 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5001 gameseq_set_state(GS_STATE_MAIN_MENU);
5006 Player_multi_died_check = -1;
5009 case GS_EVENT_QUIT_GAME:
5010 main_hall_stop_music();
5011 main_hall_stop_ambient();
5012 gameseq_set_state(GS_STATE_QUIT_GAME);
5014 Player_multi_died_check = -1;
5017 case GS_EVENT_GAMEPLAY_HELP:
5018 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5021 case GS_EVENT_PAUSE_GAME:
5022 gameseq_push_state(GS_STATE_GAME_PAUSED);
5025 case GS_EVENT_DEBUG_PAUSE_GAME:
5026 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5029 case GS_EVENT_TRAINING_PAUSE:
5030 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5033 case GS_EVENT_PREVIOUS_STATE:
5034 gameseq_pop_state();
5037 case GS_EVENT_TOGGLE_FULLSCREEN:
5038 #ifndef HARDWARE_ONLY
5040 if ( gr_screen.mode == GR_SOFTWARE ) {
5041 gr_init( GR_640, GR_DIRECTDRAW );
5042 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5043 gr_init( GR_640, GR_SOFTWARE );
5049 case GS_EVENT_TOGGLE_GLIDE:
5051 if ( gr_screen.mode != GR_GLIDE ) {
5052 gr_init( GR_640, GR_GLIDE );
5054 gr_init( GR_640, GR_SOFTWARE );
5059 case GS_EVENT_LOAD_MISSION_MENU:
5060 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5063 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5064 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5067 case GS_EVENT_HUD_CONFIG:
5068 gameseq_push_state( GS_STATE_HUD_CONFIG );
5071 case GS_EVENT_CONTROL_CONFIG:
5072 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5075 case GS_EVENT_DEATH_DIED:
5076 gameseq_set_state( GS_STATE_DEATH_DIED );
5079 case GS_EVENT_DEATH_BLEW_UP:
5080 if ( current_state == GS_STATE_DEATH_DIED ) {
5081 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5082 event_music_player_death();
5084 // multiplayer clients set their extra check here
5085 if(Game_mode & GM_MULTIPLAYER){
5086 // set the multi died absolute last chance check
5087 Player_multi_died_check = time(NULL);
5090 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5094 case GS_EVENT_NEW_CAMPAIGN:
5095 if (!mission_load_up_campaign()){
5096 readyroom_continue_campaign();
5099 Player_multi_died_check = -1;
5102 case GS_EVENT_CAMPAIGN_CHEAT:
5103 if (!mission_load_up_campaign()){
5105 // bash campaign value
5106 extern char Main_hall_campaign_cheat[512];
5109 // look for the mission
5110 for(idx=0; idx<Campaign.num_missions; idx++){
5111 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5112 Campaign.next_mission = idx;
5113 Campaign.prev_mission = idx - 1;
5120 readyroom_continue_campaign();
5123 Player_multi_died_check = -1;
5126 case GS_EVENT_CAMPAIGN_ROOM:
5127 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5130 case GS_EVENT_CMD_BRIEF:
5131 gameseq_set_state(GS_STATE_CMD_BRIEF);
5134 case GS_EVENT_RED_ALERT:
5135 gameseq_set_state(GS_STATE_RED_ALERT);
5138 case GS_EVENT_CREDITS:
5139 gameseq_set_state( GS_STATE_CREDITS );
5142 case GS_EVENT_VIEW_MEDALS:
5143 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5146 case GS_EVENT_SHOW_GOALS:
5147 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5150 case GS_EVENT_HOTKEY_SCREEN:
5151 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5154 // multiplayer stuff follow these comments
5156 case GS_EVENT_MULTI_JOIN_GAME:
5157 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5160 case GS_EVENT_MULTI_HOST_SETUP:
5161 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5164 case GS_EVENT_MULTI_CLIENT_SETUP:
5165 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5168 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5169 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5172 case GS_EVENT_MULTI_STD_WAIT:
5173 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5176 case GS_EVENT_STANDALONE_MAIN:
5177 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5180 case GS_EVENT_MULTI_PAUSE:
5181 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5184 case GS_EVENT_INGAME_PRE_JOIN:
5185 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5188 case GS_EVENT_EVENT_DEBUG:
5189 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5192 // Start a warpout where player automatically goes 70 no matter what
5193 // and can't cancel out of it.
5194 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5195 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5197 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5198 Player->saved_viewer_mode = Viewer_mode;
5199 Player->control_mode = PCM_WARPOUT_STAGE1;
5200 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5201 Warpout_time = 0.0f; // Start timer!
5204 case GS_EVENT_PLAYER_WARPOUT_START:
5205 if ( Player->control_mode != PCM_NORMAL ) {
5206 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5208 Player->saved_viewer_mode = Viewer_mode;
5209 Player->control_mode = PCM_WARPOUT_STAGE1;
5210 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5211 Warpout_time = 0.0f; // Start timer!
5212 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5216 case GS_EVENT_PLAYER_WARPOUT_STOP:
5217 if ( Player->control_mode != PCM_NORMAL ) {
5218 if ( !Warpout_forced ) { // cannot cancel forced warpout
5219 Player->control_mode = PCM_NORMAL;
5220 Viewer_mode = Player->saved_viewer_mode;
5221 hud_subspace_notify_abort();
5222 mprintf(( "Player put back to normal mode.\n" ));
5223 if ( Warpout_sound > -1 ) {
5224 snd_stop( Warpout_sound );
5231 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5232 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5233 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5234 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5236 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5237 shipfx_warpout_start( Player_obj );
5238 Player->control_mode = PCM_WARPOUT_STAGE2;
5239 Player->saved_viewer_mode = Viewer_mode;
5240 Viewer_mode |= VM_WARP_CHASE;
5242 vector tmp = Player_obj->pos;
5244 ship_get_eye( &tmp, &tmp_m, Player_obj );
5245 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5246 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5247 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5249 camera_set_position( &tmp );
5250 camera_set_orient( &Player_obj->orient );
5251 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5253 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5254 camera_set_velocity( &tmp_vel, 1);
5258 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5259 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5260 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5261 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5263 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5264 Player->control_mode = PCM_WARPOUT_STAGE3;
5268 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5269 mprintf(( "Player warped out. Going to debriefing!\n" ));
5270 Player->control_mode = PCM_NORMAL;
5271 Viewer_mode = Player->saved_viewer_mode;
5274 // we have a special debriefing screen for multiplayer furballs
5275 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5276 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5278 // do the normal debriefing for all other situations
5280 gameseq_post_event(GS_EVENT_DEBRIEF);
5284 case GS_EVENT_STANDALONE_POSTGAME:
5285 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5288 case GS_EVENT_INITIAL_PLAYER_SELECT:
5289 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5292 case GS_EVENT_GAME_INIT:
5293 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5294 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5296 // see if the command line option has been set to use the last pilot, and act acoordingly
5297 if( player_select_get_last_pilot() ) {
5298 // always enter the main menu -- do the automatic network startup stuff elsewhere
5299 // so that we still have valid checks for networking modes, etc.
5300 gameseq_set_state(GS_STATE_MAIN_MENU);
5302 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5307 case GS_EVENT_MULTI_MISSION_SYNC:
5308 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5311 case GS_EVENT_MULTI_START_GAME:
5312 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5315 case GS_EVENT_MULTI_HOST_OPTIONS:
5316 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5319 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5320 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5323 case GS_EVENT_TEAM_SELECT:
5324 gameseq_set_state(GS_STATE_TEAM_SELECT);
5327 case GS_EVENT_END_CAMPAIGN:
5328 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5331 case GS_EVENT_END_DEMO:
5332 gameseq_set_state(GS_STATE_END_DEMO);
5335 case GS_EVENT_LOOP_BRIEF:
5336 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5345 // Called when a state is being left.
5346 // The current state is still at old_state, but as soon as
5347 // this function leaves, then the current state will become
5348 // new state. You should never try to change the state
5349 // in here... if you think you need to, you probably really
5350 // need to post an event, not change the state.
5351 void game_leave_state( int old_state, int new_state )
5353 int end_mission = 1;
5355 switch (new_state) {
5356 case GS_STATE_GAME_PAUSED:
5357 case GS_STATE_DEBUG_PAUSED:
5358 case GS_STATE_OPTIONS_MENU:
5359 case GS_STATE_CONTROL_CONFIG:
5360 case GS_STATE_MISSION_LOG_SCROLLBACK:
5361 case GS_STATE_DEATH_DIED:
5362 case GS_STATE_SHOW_GOALS:
5363 case GS_STATE_HOTKEY_SCREEN:
5364 case GS_STATE_MULTI_PAUSED:
5365 case GS_STATE_TRAINING_PAUSED:
5366 case GS_STATE_EVENT_DEBUG:
5367 case GS_STATE_GAMEPLAY_HELP:
5368 end_mission = 0; // these events shouldn't end a mission
5372 switch (old_state) {
5373 case GS_STATE_BRIEFING:
5374 brief_stop_voices();
5375 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5376 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5377 && (new_state != GS_STATE_TEAM_SELECT) ){
5378 common_select_close();
5379 if ( new_state == GS_STATE_MAIN_MENU ) {
5380 freespace_stop_mission();
5384 // COMMAND LINE OPTION
5385 if (Cmdline_multi_stream_chat_to_file){
5386 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5387 cfclose(Multi_chat_stream);
5391 case GS_STATE_DEBRIEF:
5392 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5397 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5398 multi_df_debrief_close();
5401 case GS_STATE_LOAD_MISSION_MENU:
5402 mission_load_menu_close();
5405 case GS_STATE_SIMULATOR_ROOM:
5409 case GS_STATE_CAMPAIGN_ROOM:
5410 campaign_room_close();
5413 case GS_STATE_CMD_BRIEF:
5414 if (new_state == GS_STATE_OPTIONS_MENU) {
5419 if (new_state == GS_STATE_MAIN_MENU)
5420 freespace_stop_mission();
5425 case GS_STATE_RED_ALERT:
5429 case GS_STATE_SHIP_SELECT:
5430 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5431 new_state != GS_STATE_HOTKEY_SCREEN &&
5432 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5433 common_select_close();
5434 if ( new_state == GS_STATE_MAIN_MENU ) {
5435 freespace_stop_mission();
5440 case GS_STATE_WEAPON_SELECT:
5441 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5442 new_state != GS_STATE_HOTKEY_SCREEN &&
5443 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5444 common_select_close();
5445 if ( new_state == GS_STATE_MAIN_MENU ) {
5446 freespace_stop_mission();
5451 case GS_STATE_TEAM_SELECT:
5452 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5453 new_state != GS_STATE_HOTKEY_SCREEN &&
5454 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5455 common_select_close();
5456 if ( new_state == GS_STATE_MAIN_MENU ) {
5457 freespace_stop_mission();
5462 case GS_STATE_MAIN_MENU:
5463 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5470 case GS_STATE_OPTIONS_MENU:
5471 //game_start_time();
5472 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5473 multi_join_clear_game_list();
5475 options_menu_close();
5478 case GS_STATE_BARRACKS_MENU:
5479 if(new_state != GS_STATE_VIEW_MEDALS){
5484 case GS_STATE_MISSION_LOG_SCROLLBACK:
5485 hud_scrollback_close();
5488 case GS_STATE_TRAINING_MENU:
5489 training_menu_close();
5492 case GS_STATE_GAME_PLAY:
5493 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5494 player_save_target_and_weapon_link_prefs();
5495 game_stop_looped_sounds();
5498 sound_env_disable();
5499 joy_ff_stop_effects();
5501 // stop game time under certain conditions
5502 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5507 // shut down any recording or playing demos
5512 // when in multiplayer and going back to the main menu, send a leave game packet
5513 // right away (before calling stop mission). stop_mission was taking to long to
5514 // close mission down and I want people to get notified ASAP.
5515 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5516 multi_quit_game(PROMPT_NONE);
5519 freespace_stop_mission();
5520 Game_time_compression = F1_0;
5524 case GS_STATE_TECH_MENU:
5528 case GS_STATE_TRAINING_PAUSED:
5529 Training_num_lines = 0;
5530 // fall through to GS_STATE_GAME_PAUSED
5532 case GS_STATE_GAME_PAUSED:
5534 if ( end_mission ) {
5539 case GS_STATE_DEBUG_PAUSED:
5542 pause_debug_close();
5546 case GS_STATE_HUD_CONFIG:
5550 // join/start a game
5551 case GS_STATE_MULTI_JOIN_GAME:
5552 if(new_state != GS_STATE_OPTIONS_MENU){
5553 multi_join_game_close();
5557 case GS_STATE_MULTI_HOST_SETUP:
5558 case GS_STATE_MULTI_CLIENT_SETUP:
5559 // if this is just the host going into the options screen, don't do anything
5560 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5564 // close down the proper state
5565 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5566 multi_create_game_close();
5568 multi_game_client_setup_close();
5571 // COMMAND LINE OPTION
5572 if (Cmdline_multi_stream_chat_to_file){
5573 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5574 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5575 cfclose(Multi_chat_stream);
5580 case GS_STATE_CONTROL_CONFIG:
5581 control_config_close();
5584 case GS_STATE_DEATH_DIED:
5585 Game_mode &= ~GM_DEAD_DIED;
5587 // early end while respawning or blowing up in a multiplayer game
5588 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5590 freespace_stop_mission();
5594 case GS_STATE_DEATH_BLEW_UP:
5595 Game_mode &= ~GM_DEAD_BLEW_UP;
5597 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5598 // to determine if I should do anything.
5599 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5601 freespace_stop_mission();
5604 // if we are not respawing as an observer or as a player, our new state will not
5605 // be gameplay state.
5606 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5607 game_stop_time(); // hasn't been called yet!!
5608 freespace_stop_mission();
5614 case GS_STATE_CREDITS:
5618 case GS_STATE_VIEW_MEDALS:
5622 case GS_STATE_SHOW_GOALS:
5623 mission_show_goals_close();
5626 case GS_STATE_HOTKEY_SCREEN:
5627 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5628 mission_hotkey_close();
5632 case GS_STATE_MULTI_MISSION_SYNC:
5633 // if we're moving into the options menu, don't do anything
5634 if(new_state == GS_STATE_OPTIONS_MENU){
5638 Assert( Game_mode & GM_MULTIPLAYER );
5640 if ( new_state == GS_STATE_GAME_PLAY ){
5641 // palette_restore_palette();
5643 // change a couple of flags to indicate our state!!!
5644 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5645 send_netplayer_update_packet();
5647 // set the game mode
5648 Game_mode |= GM_IN_MISSION;
5652 case GS_STATE_VIEW_CUTSCENES:
5653 cutscenes_screen_close();
5656 case GS_STATE_MULTI_STD_WAIT:
5657 multi_standalone_wait_close();
5660 case GS_STATE_STANDALONE_MAIN:
5661 standalone_main_close();
5662 if(new_state == GS_STATE_MULTI_STD_WAIT){
5663 init_multiplayer_stats();
5667 case GS_STATE_MULTI_PAUSED:
5668 // if ( end_mission ){
5673 case GS_STATE_INGAME_PRE_JOIN:
5674 multi_ingame_select_close();
5677 case GS_STATE_STANDALONE_POSTGAME:
5678 multi_standalone_postgame_close();
5681 case GS_STATE_INITIAL_PLAYER_SELECT:
5682 player_select_close();
5685 case GS_STATE_MULTI_START_GAME:
5686 multi_start_game_close();
5689 case GS_STATE_MULTI_HOST_OPTIONS:
5690 multi_host_options_close();
5693 case GS_STATE_END_OF_CAMPAIGN:
5694 mission_campaign_end_close();
5697 case GS_STATE_LOOP_BRIEF:
5703 // Called when a state is being entered.
5704 // The current state is set to the state we're entering at
5705 // this point, and old_state is set to the state we're coming
5706 // from. You should never try to change the state
5707 // in here... if you think you need to, you probably really
5708 // need to post an event, not change the state.
5710 void game_enter_state( int old_state, int new_state )
5712 switch (new_state) {
5713 case GS_STATE_MAIN_MENU:
5714 // in multiplayer mode, be sure that we are not doing networking anymore.
5715 if ( Game_mode & GM_MULTIPLAYER ) {
5716 Assert( Net_player != NULL );
5717 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5720 Game_time_compression = F1_0;
5722 // determine which ship this guy is currently based on
5723 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5726 if (Player->on_bastion) {
5734 case GS_STATE_BRIEFING:
5735 main_hall_stop_music();
5736 main_hall_stop_ambient();
5738 if (Game_mode & GM_NORMAL) {
5739 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5740 // MWA: or from options or hotkey screens
5741 // JH: or if the command brief state already did this
5742 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5743 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5744 && (old_state != GS_STATE_CMD_BRIEF) ) {
5745 if ( !game_start_mission() ) // this should put us into a new state on failure!
5749 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5750 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5751 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5753 Game_time_compression = F1_0;
5755 if ( red_alert_mission() ) {
5756 gameseq_post_event(GS_EVENT_RED_ALERT);
5763 case GS_STATE_DEBRIEF:
5764 game_stop_looped_sounds();
5765 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5766 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5771 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5772 multi_df_debrief_init();
5775 case GS_STATE_LOAD_MISSION_MENU:
5776 mission_load_menu_init();
5779 case GS_STATE_SIMULATOR_ROOM:
5783 case GS_STATE_CAMPAIGN_ROOM:
5784 campaign_room_init();
5787 case GS_STATE_RED_ALERT:
5788 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5792 case GS_STATE_CMD_BRIEF: {
5793 int team_num = 0; // team number used as index for which cmd brief to use.
5795 if (old_state == GS_STATE_OPTIONS_MENU) {
5799 main_hall_stop_music();
5800 main_hall_stop_ambient();
5802 if (Game_mode & GM_NORMAL) {
5803 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5804 // MWA: or from options or hotkey screens
5805 // JH: or if the command brief state already did this
5806 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5807 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5808 if ( !game_start_mission() ) // this should put us into a new state on failure!
5813 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5814 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5815 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5817 cmd_brief_init(team_num);
5823 case GS_STATE_SHIP_SELECT:
5827 case GS_STATE_WEAPON_SELECT:
5828 weapon_select_init();
5831 case GS_STATE_TEAM_SELECT:
5835 case GS_STATE_GAME_PAUSED:
5840 case GS_STATE_DEBUG_PAUSED:
5841 // game_stop_time();
5842 // os_set_title("FreeSpace - PAUSED");
5845 case GS_STATE_TRAINING_PAUSED:
5852 case GS_STATE_OPTIONS_MENU:
5854 options_menu_init();
5857 case GS_STATE_GAME_PLAY:
5858 // coming from the gameplay state or the main menu, we might need to load the mission
5859 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5860 if ( !game_start_mission() ) // this should put us into a new state.
5865 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5866 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5867 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5868 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5869 (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) ) {
5870 // JAS: Used to do all paging here.
5874 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5878 main_hall_stop_music();
5879 main_hall_stop_ambient();
5880 event_music_first_pattern(); // start the first pattern
5883 // special code that restores player ship selection and weapons loadout when doing a quick start
5884 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5885 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5886 wss_direct_restore_loadout();
5890 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5891 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5892 event_music_first_pattern(); // start the first pattern
5895 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5896 event_music_first_pattern(); // start the first pattern
5898 player_restore_target_and_weapon_link_prefs();
5900 Game_mode |= GM_IN_MISSION;
5903 // required to truely make mouse deltas zeroed in debug mouse code
5904 void mouse_force_pos(int x, int y);
5905 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5910 // only start time if in single player, or coming from multi wait state
5913 (Game_mode & GM_NORMAL) &&
5914 (old_state != GS_STATE_VIEW_CUTSCENES)
5916 (Game_mode & GM_MULTIPLAYER) && (
5917 (old_state == GS_STATE_MULTI_PAUSED) ||
5918 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5924 // when coming from the multi paused state, reset the timestamps
5925 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5926 multi_reset_timestamps();
5929 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5930 // initialize all object update details
5931 multi_oo_gameplay_init();
5934 // under certain circumstances, the server should reset the object update rate limiting stuff
5935 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5936 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5938 // reinitialize the rate limiting system for all clients
5939 multi_oo_rate_init_all();
5942 // multiplayer clients should always re-initialize their control info rate limiting system
5943 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5944 multi_oo_rate_init_all();
5948 if(Game_mode & GM_MULTIPLAYER){
5949 multi_ping_reset_players();
5952 Game_subspace_effect = 0;
5953 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5954 Game_subspace_effect = 1;
5955 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5956 game_start_subspace_ambient_sound();
5960 sound_env_set(&Game_sound_env);
5961 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5963 // clear multiplayer button info i
5964 extern button_info Multi_ship_status_bi;
5965 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5968 case GS_STATE_HUD_CONFIG:
5972 case GS_STATE_MULTI_JOIN_GAME:
5973 multi_join_clear_game_list();
5975 if (old_state != GS_STATE_OPTIONS_MENU) {
5976 multi_join_game_init();
5981 case GS_STATE_MULTI_HOST_SETUP:
5982 // don't reinitialize if we're coming back from the host options screen
5983 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5984 multi_create_game_init();
5989 case GS_STATE_MULTI_CLIENT_SETUP:
5990 if (old_state != GS_STATE_OPTIONS_MENU) {
5991 multi_game_client_setup_init();
5996 case GS_STATE_CONTROL_CONFIG:
5997 control_config_init();
6000 case GS_STATE_TECH_MENU:
6004 case GS_STATE_BARRACKS_MENU:
6005 if(old_state != GS_STATE_VIEW_MEDALS){
6010 case GS_STATE_MISSION_LOG_SCROLLBACK:
6011 hud_scrollback_init();
6014 case GS_STATE_DEATH_DIED:
6015 Player_died_time = timestamp(10);
6017 if(!(Game_mode & GM_MULTIPLAYER)){
6018 player_show_death_message();
6020 Game_mode |= GM_DEAD_DIED;
6023 case GS_STATE_DEATH_BLEW_UP:
6024 if ( !popupdead_is_active() ) {
6025 Player_ai->target_objnum = -1;
6028 // stop any local EMP effect
6031 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6032 Game_mode |= GM_DEAD_BLEW_UP;
6033 Show_viewing_from_self = 0;
6035 // timestamp how long we should wait before displaying the died popup
6036 if ( !popupdead_is_active() ) {
6037 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6041 case GS_STATE_GAMEPLAY_HELP:
6042 gameplay_help_init();
6045 case GS_STATE_CREDITS:
6046 main_hall_stop_music();
6047 main_hall_stop_ambient();
6051 case GS_STATE_VIEW_MEDALS:
6052 medal_main_init(Player);
6055 case GS_STATE_SHOW_GOALS:
6056 mission_show_goals_init();
6059 case GS_STATE_HOTKEY_SCREEN:
6060 mission_hotkey_init();
6063 case GS_STATE_MULTI_MISSION_SYNC:
6064 // if we're coming from the options screen, don't do any
6065 if(old_state == GS_STATE_OPTIONS_MENU){
6069 switch(Multi_sync_mode){
6070 case MULTI_SYNC_PRE_BRIEFING:
6071 // if moving from game forming to the team select state
6074 case MULTI_SYNC_POST_BRIEFING:
6075 // if moving from briefing into the mission itself
6078 // tell everyone that we're now loading data
6079 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6080 send_netplayer_update_packet();
6082 // JAS: Used to do all paging here!!!!
6084 Net_player->state = NETPLAYER_STATE_WAITING;
6085 send_netplayer_update_packet();
6087 Game_time_compression = F1_0;
6089 case MULTI_SYNC_INGAME:
6095 case GS_STATE_VIEW_CUTSCENES:
6096 cutscenes_screen_init();
6099 case GS_STATE_MULTI_STD_WAIT:
6100 multi_standalone_wait_init();
6103 case GS_STATE_STANDALONE_MAIN:
6104 // don't initialize if we're coming from one of these 2 states unless there are no
6105 // players left (reset situation)
6106 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6107 standalone_main_init();
6111 case GS_STATE_MULTI_PAUSED:
6115 case GS_STATE_INGAME_PRE_JOIN:
6116 multi_ingame_select_init();
6119 case GS_STATE_STANDALONE_POSTGAME:
6120 multi_standalone_postgame_init();
6123 case GS_STATE_INITIAL_PLAYER_SELECT:
6124 player_select_init();
6127 case GS_STATE_MULTI_START_GAME:
6128 multi_start_game_init();
6131 case GS_STATE_MULTI_HOST_OPTIONS:
6132 multi_host_options_init();
6135 case GS_STATE_END_OF_CAMPAIGN:
6136 mission_campaign_end_init();
6139 case GS_STATE_LOOP_BRIEF:
6146 // do stuff that may need to be done regardless of state
6147 void game_do_state_common(int state,int no_networking)
6149 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6150 snd_do_frame(); // update sound system
6151 event_music_do_frame(); // music needs to play across many states
6153 multi_log_process();
6155 if (no_networking) {
6159 // maybe do a multiplayer frame based on game mode and state type
6160 if (Game_mode & GM_MULTIPLAYER) {
6162 case GS_STATE_OPTIONS_MENU:
6163 case GS_STATE_GAMEPLAY_HELP:
6164 case GS_STATE_HOTKEY_SCREEN:
6165 case GS_STATE_HUD_CONFIG:
6166 case GS_STATE_CONTROL_CONFIG:
6167 case GS_STATE_MISSION_LOG_SCROLLBACK:
6168 case GS_STATE_SHOW_GOALS:
6169 case GS_STATE_VIEW_CUTSCENES:
6170 case GS_STATE_EVENT_DEBUG:
6171 multi_maybe_do_frame();
6175 game_do_networking();
6179 // Called once a frame.
6180 // You should never try to change the state
6181 // in here... if you think you need to, you probably really
6182 // need to post an event, not change the state.
6183 int Game_do_state_should_skip = 0;
6184 void game_do_state(int state)
6186 // always lets the do_state_common() function determine if the state should be skipped
6187 Game_do_state_should_skip = 0;
6189 // legal to set the should skip state anywhere in this function
6190 game_do_state_common(state); // do stuff that may need to be done regardless of state
6192 if(Game_do_state_should_skip){
6197 case GS_STATE_MAIN_MENU:
6198 game_set_frametime(GS_STATE_MAIN_MENU);
6199 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6202 main_hall_do(flFrametime);
6206 case GS_STATE_OPTIONS_MENU:
6207 game_set_frametime(GS_STATE_OPTIONS_MENU);
6208 options_menu_do_frame(flFrametime);
6211 case GS_STATE_BARRACKS_MENU:
6212 game_set_frametime(GS_STATE_BARRACKS_MENU);
6213 barracks_do_frame(flFrametime);
6216 case GS_STATE_TRAINING_MENU:
6217 game_set_frametime(GS_STATE_TRAINING_MENU);
6218 training_menu_do_frame(flFrametime);
6221 case GS_STATE_TECH_MENU:
6222 game_set_frametime(GS_STATE_TECH_MENU);
6223 techroom_do_frame(flFrametime);
6226 case GS_STATE_GAMEPLAY_HELP:
6227 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6228 gameplay_help_do_frame(flFrametime);
6231 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6235 case GS_STATE_GAME_PAUSED:
6239 case GS_STATE_DEBUG_PAUSED:
6241 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6246 case GS_STATE_TRAINING_PAUSED:
6247 game_training_pause_do();
6250 case GS_STATE_LOAD_MISSION_MENU:
6251 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6252 mission_load_menu_do();
6255 case GS_STATE_BRIEFING:
6256 game_set_frametime(GS_STATE_BRIEFING);
6257 brief_do_frame(flFrametime);
6260 case GS_STATE_DEBRIEF:
6261 game_set_frametime(GS_STATE_DEBRIEF);
6262 debrief_do_frame(flFrametime);
6265 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6266 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6267 multi_df_debrief_do();
6270 case GS_STATE_SHIP_SELECT:
6271 game_set_frametime(GS_STATE_SHIP_SELECT);
6272 ship_select_do(flFrametime);
6275 case GS_STATE_WEAPON_SELECT:
6276 game_set_frametime(GS_STATE_WEAPON_SELECT);
6277 weapon_select_do(flFrametime);
6280 case GS_STATE_MISSION_LOG_SCROLLBACK:
6281 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6282 hud_scrollback_do_frame(flFrametime);
6285 case GS_STATE_HUD_CONFIG:
6286 game_set_frametime(GS_STATE_HUD_CONFIG);
6287 hud_config_do_frame(flFrametime);
6290 case GS_STATE_MULTI_JOIN_GAME:
6291 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6292 multi_join_game_do_frame();
6295 case GS_STATE_MULTI_HOST_SETUP:
6296 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6297 multi_create_game_do();
6300 case GS_STATE_MULTI_CLIENT_SETUP:
6301 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6302 multi_game_client_setup_do_frame();
6305 case GS_STATE_CONTROL_CONFIG:
6306 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6307 control_config_do_frame(flFrametime);
6310 case GS_STATE_DEATH_DIED:
6314 case GS_STATE_DEATH_BLEW_UP:
6318 case GS_STATE_SIMULATOR_ROOM:
6319 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6320 sim_room_do_frame(flFrametime);
6323 case GS_STATE_CAMPAIGN_ROOM:
6324 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6325 campaign_room_do_frame(flFrametime);
6328 case GS_STATE_RED_ALERT:
6329 game_set_frametime(GS_STATE_RED_ALERT);
6330 red_alert_do_frame(flFrametime);
6333 case GS_STATE_CMD_BRIEF:
6334 game_set_frametime(GS_STATE_CMD_BRIEF);
6335 cmd_brief_do_frame(flFrametime);
6338 case GS_STATE_CREDITS:
6339 game_set_frametime(GS_STATE_CREDITS);
6340 credits_do_frame(flFrametime);
6343 case GS_STATE_VIEW_MEDALS:
6344 game_set_frametime(GS_STATE_VIEW_MEDALS);
6348 case GS_STATE_SHOW_GOALS:
6349 game_set_frametime(GS_STATE_SHOW_GOALS);
6350 mission_show_goals_do_frame(flFrametime);
6353 case GS_STATE_HOTKEY_SCREEN:
6354 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6355 mission_hotkey_do_frame(flFrametime);
6358 case GS_STATE_VIEW_CUTSCENES:
6359 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6360 cutscenes_screen_do_frame();
6363 case GS_STATE_MULTI_STD_WAIT:
6364 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6365 multi_standalone_wait_do();
6368 case GS_STATE_STANDALONE_MAIN:
6369 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6370 standalone_main_do();
6373 case GS_STATE_MULTI_PAUSED:
6374 game_set_frametime(GS_STATE_MULTI_PAUSED);
6378 case GS_STATE_TEAM_SELECT:
6379 game_set_frametime(GS_STATE_TEAM_SELECT);
6383 case GS_STATE_INGAME_PRE_JOIN:
6384 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6385 multi_ingame_select_do();
6388 case GS_STATE_EVENT_DEBUG:
6390 game_set_frametime(GS_STATE_EVENT_DEBUG);
6391 game_show_event_debug(flFrametime);
6395 case GS_STATE_STANDALONE_POSTGAME:
6396 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6397 multi_standalone_postgame_do();
6400 case GS_STATE_INITIAL_PLAYER_SELECT:
6401 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6405 case GS_STATE_MULTI_MISSION_SYNC:
6406 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6410 case GS_STATE_MULTI_START_GAME:
6411 game_set_frametime(GS_STATE_MULTI_START_GAME);
6412 multi_start_game_do();
6415 case GS_STATE_MULTI_HOST_OPTIONS:
6416 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6417 multi_host_options_do();
6420 case GS_STATE_END_OF_CAMPAIGN:
6421 mission_campaign_end_do();
6424 case GS_STATE_END_DEMO:
6425 game_set_frametime(GS_STATE_END_DEMO);
6426 end_demo_campaign_do();
6429 case GS_STATE_LOOP_BRIEF:
6430 game_set_frametime(GS_STATE_LOOP_BRIEF);
6434 } // end switch(gs_current_state)
6438 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6439 int game_do_ram_check(int ram_in_bytes)
6441 if ( ram_in_bytes < 30*1024*1024 ) {
6442 int allowed_to_run = 1;
6443 if ( ram_in_bytes < 25*1024*1024 ) {
6448 int Freespace_total_ram_MB;
6449 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6451 if ( allowed_to_run ) {
6453 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);
6457 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6458 if ( msgbox_rval == IDCANCEL ) {
6465 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);
6467 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6478 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6479 // If so, copy it over and remove the update directory.
6480 void game_maybe_update_launcher(char *exe_dir)
6483 char src_filename[MAX_PATH];
6484 char dest_filename[MAX_PATH];
6486 strcpy(src_filename, exe_dir);
6487 strcat(src_filename, NOX("\\update\\freespace.exe"));
6489 strcpy(dest_filename, exe_dir);
6490 strcat(dest_filename, NOX("\\freespace.exe"));
6492 // see if src_filename exists
6494 fp = fopen(src_filename, "rb");
6500 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6502 // copy updated freespace.exe to freespace exe dir
6503 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6504 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 );
6508 // delete the file in the update directory
6509 DeleteFile(src_filename);
6511 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6512 char update_dir[MAX_PATH];
6513 strcpy(update_dir, exe_dir);
6514 strcat(update_dir, NOX("\\update"));
6515 RemoveDirectory(update_dir);
6521 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6525 int sub_total_destroyed = 0;
6529 // get the total for all his children
6530 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6531 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6534 // find the # of faces for this _individual_ object
6535 total = submodel_get_num_polys(model_num, sm);
6536 if(strstr(pm->submodel[sm].name, "-destroyed")){
6537 sub_total_destroyed = total;
6541 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6544 *out_total += total + sub_total;
6545 *out_destroyed_total += sub_total_destroyed;
6548 #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);
6549 void game_spew_pof_info()
6551 char *pof_list[1000];
6554 int idx, model_num, i, j;
6556 int total, root_total, model_total, destroyed_total, counted;
6560 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6562 // spew info on all the pofs
6568 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6573 for(idx=0; idx<num_files; idx++, counted++){
6574 sprintf(str, "%s.pof", pof_list[idx]);
6575 model_num = model_load(str, 0, NULL);
6577 pm = model_get(model_num);
6579 // if we have a real model
6584 // go through and print all raw submodels
6585 cfputs("RAW\n", out);
6588 for (i=0; i<pm->n_models; i++) {
6589 total = submodel_get_num_polys(model_num, i);
6591 model_total += total;
6592 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6595 sprintf(str, "Model total %d\n", model_total);
6598 // now go through and do it by LOD
6599 cfputs("BY LOD\n\n", out);
6600 for(i=0; i<pm->n_detail_levels; i++){
6601 sprintf(str, "LOD %d\n", i);
6605 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6607 destroyed_total = 0;
6608 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6609 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6612 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6615 sprintf(str, "TOTAL: %d\n", total + root_total);
6617 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6619 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6622 cfputs("------------------------------------------------------------------------\n\n", out);
6626 if(counted >= MAX_POLYGON_MODELS - 5){
6639 game_spew_pof_info();
6642 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6647 // Don't let more than one instance of Freespace run.
6648 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6650 SetForegroundWindow(hwnd);
6655 // Find out how much RAM is on this machine
6658 ms.dwLength = sizeof(MEMORYSTATUS);
6659 GlobalMemoryStatus(&ms);
6660 Freespace_total_ram = ms.dwTotalPhys;
6662 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6666 if ( ms.dwTotalVirtual < 1024 ) {
6667 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6671 if (!vm_init(24*1024*1024)) {
6672 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 );
6676 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6678 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);
6688 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6689 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6690 seem worth bothering with.
6694 lResult = RegOpenKeyEx(
6695 HKEY_LOCAL_MACHINE, // Where it is
6696 "Software\\Microsoft\\DirectX", // name of key
6697 NULL, // DWORD reserved
6698 KEY_QUERY_VALUE, // Allows all changes
6699 &hKey // Location to store key
6702 if (lResult == ERROR_SUCCESS) {
6704 DWORD dwType, dwLen;
6707 lResult = RegQueryValueEx(
6708 hKey, // Handle to key
6709 "Version", // The values name
6710 NULL, // DWORD reserved
6711 &dwType, // What kind it is
6712 (ubyte *) version, // value to set
6713 &dwLen // How many bytes to set
6716 if (lResult == ERROR_SUCCESS) {
6717 dx_version = atoi(strstr(version, ".") + 1);
6721 DWORD dwType, dwLen;
6724 lResult = RegQueryValueEx(
6725 hKey, // Handle to key
6726 "InstalledVersion", // The values name
6727 NULL, // DWORD reserved
6728 &dwType, // What kind it is
6729 (ubyte *) &val, // value to set
6730 &dwLen // How many bytes to set
6733 if (lResult == ERROR_SUCCESS) {
6741 if (dx_version < 3) {
6742 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6743 "latest version of DirectX at:\n\n"
6744 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6746 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6747 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6752 //=====================================================
6753 // Make sure we're running in the right directory.
6757 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6758 char *p = exe_dir + strlen(exe_dir);
6760 // chop off the filename
6761 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6767 if ( strlen(exe_dir) > 0 ) {
6768 SetCurrentDirectory(exe_dir);
6771 // check for updated freespace.exe
6772 game_maybe_update_launcher(exe_dir);
6780 extern void windebug_memwatch_init();
6781 windebug_memwatch_init();
6785 parse_cmdline(szCmdLine);
6787 #ifdef STANDALONE_ONLY_BUILD
6789 nprintf(("Network", "Standalone running"));
6792 nprintf(("Network", "Standalone running"));
6800 // maybe spew pof stuff
6801 if(Cmdline_spew_pof_info){
6802 game_spew_pof_info();
6807 // non-demo, non-standalone, play the intro movie
6812 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) ){
6814 #if defined(OEM_BUILD)
6815 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6817 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6818 #endif // defined(OEM_BUILD)
6823 if ( !Is_standalone ) {
6825 // release -- movies always play
6828 // 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
6830 // movie_play( NOX("intro.mve"), 0 );
6832 // debug version, movie will only play with -showmovies
6833 #elif !defined(NDEBUG)
6836 // movie_play( NOX("intro.mve"), 0);
6839 if ( Cmdline_show_movies )
6840 movie_play( NOX("intro.mve"), 0 );
6849 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6851 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6855 // only important for non THREADED mode
6858 state = gameseq_process_events();
6859 if ( state == GS_STATE_QUIT_GAME ){
6866 demo_upsell_show_screens();
6868 #elif defined(OEM_BUILD)
6869 // show upsell screens on exit
6870 oem_upsell_show_screens();
6877 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6883 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6885 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6887 // Do nothing here - RecordExceptionInfo() has already done
6888 // everything that is needed. Actually this code won't even
6889 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6890 // the __except clause.
6896 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6897 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6903 // launcher the fslauncher program on exit
6904 void game_launch_launcher_on_exit()
6908 PROCESS_INFORMATION pi;
6909 char cmd_line[2048];
6910 char original_path[1024] = "";
6912 memset( &si, 0, sizeof(STARTUPINFO) );
6916 _getcwd(original_path, 1023);
6918 // set up command line
6919 strcpy(cmd_line, original_path);
6920 strcat(cmd_line, "\\");
6921 strcat(cmd_line, LAUNCHER_FNAME);
6922 strcat(cmd_line, " -straight_to_update");
6924 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6925 cmd_line, // pointer to command line string
6926 NULL, // pointer to process security attributes
6927 NULL, // pointer to thread security attributes
6928 FALSE, // handle inheritance flag
6929 CREATE_DEFAULT_ERROR_MODE, // creation flags
6930 NULL, // pointer to new environment block
6931 NULL, // pointer to current directory name
6932 &si, // pointer to STARTUPINFO
6933 &pi // pointer to PROCESS_INFORMATION
6935 // to eliminate build warnings
6945 // This function is called when FreeSpace terminates normally.
6947 void game_shutdown(void)
6953 // don't ever flip a page on the standalone!
6954 if(!(Game_mode & GM_STANDALONE_SERVER)){
6960 // if the player has left the "player select" screen and quit the game without actually choosing
6961 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6962 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6966 // load up common multiplayer icons
6967 multi_unload_common_icons();
6969 shockwave_close(); // release any memory used by shockwave system
6970 fireball_close(); // free fireball system
6971 ship_close(); // free any memory that was allocated for the ships
6972 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6973 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6974 bm_unload_all(); // free bitmaps
6975 mission_campaign_close(); // close out the campaign stuff
6976 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6978 #ifdef MULTI_USE_LAG
6982 // the menu close functions will unload the bitmaps if they were displayed during the game
6983 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6986 training_menu_close();
6989 extern void joy_close();
6992 audiostream_close();
6994 event_music_close();
6998 // HACKITY HACK HACK
6999 // if this flag is set, we should be firing up the launcher when exiting freespace
7000 extern int Multi_update_fireup_launcher_on_exit;
7001 if(Multi_update_fireup_launcher_on_exit){
7002 game_launch_launcher_on_exit();
7006 // game_stop_looped_sounds()
7008 // This function will call the appropriate stop looped sound functions for those
7009 // modules which use looping sounds. It is not enough just to stop a looping sound
7010 // at the DirectSound level, the game is keeping track of looping sounds, and this
7011 // function is used to inform the game that looping sounds are being halted.
7013 void game_stop_looped_sounds()
7015 hud_stop_looped_locking_sounds();
7016 hud_stop_looped_engine_sounds();
7017 afterburner_stop_sounds();
7018 player_stop_looped_sounds();
7019 obj_snd_stop_all(); // stop all object-linked persistant sounds
7020 game_stop_subspace_ambient_sound();
7021 snd_stop(Radar_static_looping);
7022 Radar_static_looping = -1;
7023 snd_stop(Target_static_looping);
7024 shipfx_stop_engine_wash_sound();
7025 Target_static_looping = -1;
7028 //////////////////////////////////////////////////////////////////////////
7030 // Code for supporting an animating mouse pointer
7033 //////////////////////////////////////////////////////////////////////////
7035 typedef struct animating_obj
7044 static animating_obj Animating_mouse;
7046 // ----------------------------------------------------------------------------
7047 // init_animating_pointer()
7049 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7050 // gets properly initialized
7052 void init_animating_pointer()
7054 Animating_mouse.first_frame = -1;
7055 Animating_mouse.num_frames = 0;
7056 Animating_mouse.current_frame = -1;
7057 Animating_mouse.time = 0.0f;
7058 Animating_mouse.elapsed_time = 0.0f;
7061 // ----------------------------------------------------------------------------
7062 // load_animating_pointer()
7064 // Called at game init to load in the frames for the animating mouse pointer
7066 // input: filename => filename of animation file that holds the animation
7068 void load_animating_pointer(char *filename, int dx, int dy)
7073 init_animating_pointer();
7075 am = &Animating_mouse;
7076 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7077 if ( am->first_frame == -1 )
7078 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7079 am->current_frame = 0;
7080 am->time = am->num_frames / i2fl(fps);
7083 // ----------------------------------------------------------------------------
7084 // unload_animating_pointer()
7086 // Called at game shutdown to free the memory used to store the animation frames
7088 void unload_animating_pointer()
7093 am = &Animating_mouse;
7094 for ( i = 0; i < am->num_frames; i++ ) {
7095 Assert( (am->first_frame+i) >= 0 );
7096 bm_release(am->first_frame + i);
7099 am->first_frame = -1;
7101 am->current_frame = -1;
7104 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7105 void game_render_mouse(float frametime)
7110 // if animating cursor exists, play the next frame
7111 am = &Animating_mouse;
7112 if ( am->first_frame != -1 ) {
7113 mouse_get_pos(&mx, &my);
7114 am->elapsed_time += frametime;
7115 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7116 if ( am->current_frame >= am->num_frames ) {
7117 am->current_frame = 0;
7118 am->elapsed_time = 0.0f;
7120 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7124 // ----------------------------------------------------------------------------
7125 // game_maybe_draw_mouse()
7127 // determines whether to draw the mouse pointer at all, and what frame of
7128 // animation to use if the mouse is animating
7130 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7132 // input: frametime => elapsed frame time in seconds since last call
7134 void game_maybe_draw_mouse(float frametime)
7138 game_state = gameseq_get_state();
7140 switch ( game_state ) {
7141 case GS_STATE_GAME_PAUSED:
7142 // case GS_STATE_MULTI_PAUSED:
7143 case GS_STATE_GAME_PLAY:
7144 case GS_STATE_DEATH_DIED:
7145 case GS_STATE_DEATH_BLEW_UP:
7146 if ( popup_active() || popupdead_is_active() ) {
7158 if ( !Mouse_hidden )
7159 game_render_mouse(frametime);
7163 void game_do_training_checks()
7167 waypoint_list *wplp;
7169 if (Training_context & TRAINING_CONTEXT_SPEED) {
7170 s = (int) Player_obj->phys_info.fspeed;
7171 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7172 if (!Training_context_speed_set) {
7173 Training_context_speed_set = 1;
7174 Training_context_speed_timestamp = timestamp();
7178 Training_context_speed_set = 0;
7181 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7182 wplp = &Waypoint_lists[Training_context_path];
7183 if (wplp->count > Training_context_goal_waypoint) {
7184 i = Training_context_goal_waypoint;
7186 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7187 if (d <= Training_context_distance) {
7188 Training_context_at_waypoint = i;
7189 if (Training_context_goal_waypoint == i) {
7190 Training_context_goal_waypoint++;
7191 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7198 if (i == wplp->count)
7201 } while (i != Training_context_goal_waypoint);
7205 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7206 Players_target = Player_ai->target_objnum;
7207 Players_targeted_subsys = Player_ai->targeted_subsys;
7208 Players_target_timestamp = timestamp();
7212 /////////// Following is for event debug view screen
7216 #define EVENT_DEBUG_MAX 5000
7217 #define EVENT_DEBUG_EVENT 0x8000
7219 int Event_debug_index[EVENT_DEBUG_MAX];
7222 void game_add_event_debug_index(int n, int indent)
7224 if (ED_count < EVENT_DEBUG_MAX)
7225 Event_debug_index[ED_count++] = n | (indent << 16);
7228 void game_add_event_debug_sexp(int n, int indent)
7233 if (Sexp_nodes[n].first >= 0) {
7234 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7235 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7239 game_add_event_debug_index(n, indent);
7240 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7241 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7243 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7246 void game_event_debug_init()
7251 for (e=0; e<Num_mission_events; e++) {
7252 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7253 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7257 void game_show_event_debug(float frametime)
7261 int font_height, font_width;
7263 static int scroll_offset = 0;
7265 k = game_check_key();
7271 if (scroll_offset < 0)
7281 scroll_offset -= 20;
7282 if (scroll_offset < 0)
7287 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7291 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7297 gr_set_color_fast(&Color_bright);
7299 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7301 gr_set_color_fast(&Color_normal);
7303 gr_get_string_size(&font_width, &font_height, NOX("test"));
7304 y_max = gr_screen.max_h - font_height - 5;
7308 while (k < ED_count) {
7309 if (y_index > y_max)
7312 z = Event_debug_index[k];
7313 if (z & EVENT_DEBUG_EVENT) {
7315 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7316 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7317 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7318 Mission_events[z].repeat_count, Mission_events[z].interval);
7326 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7327 switch (Sexp_nodes[z & 0x7fff].value) {
7329 strcat(buf, NOX(" (True)"));
7333 strcat(buf, NOX(" (False)"));
7336 case SEXP_KNOWN_TRUE:
7337 strcat(buf, NOX(" (Always true)"));
7340 case SEXP_KNOWN_FALSE:
7341 strcat(buf, NOX(" (Always false)"));
7344 case SEXP_CANT_EVAL:
7345 strcat(buf, NOX(" (Can't eval)"));
7349 case SEXP_NAN_FOREVER:
7350 strcat(buf, NOX(" (Not a number)"));
7355 gr_printf(10, y_index, buf);
7356 y_index += font_height;
7369 extern int Tmap_npixels;
7371 int Tmap_num_too_big = 0;
7372 int Num_models_needing_splitting = 0;
7374 void Time_model( int modelnum )
7376 // mprintf(( "Timing ship '%s'\n", si->name ));
7378 vector eye_pos, model_pos;
7379 matrix eye_orient, model_orient;
7381 polymodel *pm = model_get( modelnum );
7383 int l = strlen(pm->filename);
7385 if ( (l == '/') || (l=='\\') || (l==':')) {
7391 char *pof_file = &pm->filename[l];
7393 int model_needs_splitting = 0;
7395 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7397 for (i=0; i<pm->n_textures; i++ ) {
7398 char filename[1024];
7401 int bmp_num = pm->original_textures[i];
7402 if ( bmp_num > -1 ) {
7403 bm_get_palette(pm->original_textures[i], pal, filename );
7405 bm_get_info( pm->original_textures[i],&w, &h );
7408 if ( (w > 512) || (h > 512) ) {
7409 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7411 model_needs_splitting++;
7414 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7418 if ( model_needs_splitting ) {
7419 Num_models_needing_splitting++;
7421 eye_orient = model_orient = vmd_identity_matrix;
7422 eye_pos = model_pos = vmd_zero_vector;
7424 eye_pos.z = -pm->rad*2.0f;
7426 vector eye_to_model;
7428 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7429 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7431 fix t1 = timer_get_fixed_seconds();
7434 ta.p = ta.b = ta.h = 0.0f;
7439 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7441 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7443 modelstats_num_polys = modelstats_num_verts = 0;
7445 while( ta.h < PI2 ) {
7448 vm_angles_2_matrix(&m1, &ta );
7449 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7456 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7458 model_clear_instance( modelnum );
7459 model_set_detail_level(0); // use highest detail level
7460 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7468 int k = key_inkey();
7469 if ( k == KEY_ESC ) {
7474 fix t2 = timer_get_fixed_seconds();
7476 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7477 //bitmaps_used_this_frame /= framecount;
7479 modelstats_num_polys /= framecount;
7480 modelstats_num_verts /= framecount;
7482 Tmap_npixels /=framecount;
7485 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7486 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 );
7487 // 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 );
7493 int Time_models = 0;
7494 DCF_BOOL( time_models, Time_models );
7496 void Do_model_timings_test()
7500 if ( !Time_models ) return;
7502 mprintf(( "Timing models!\n" ));
7506 ubyte model_used[MAX_POLYGON_MODELS];
7507 int model_id[MAX_POLYGON_MODELS];
7508 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7513 for (i=0; i<Num_ship_types; i++ ) {
7514 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7516 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7517 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7520 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7521 if ( !Texture_fp ) return;
7523 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7524 if ( !Time_fp ) return;
7526 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7527 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7529 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7530 if ( model_used[i] ) {
7531 Time_model( model_id[i] );
7535 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7536 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7545 // Call this function when you want to inform the player that a feature is not
7546 // enabled in the DEMO version of FreSpace
7547 void game_feature_not_in_demo_popup()
7549 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7552 // format the specified time (fixed point) into a nice string
7553 void game_format_time(fix m_time,char *time_str)
7556 int hours,minutes,seconds;
7559 mtime = f2fl(m_time);
7561 // get the hours, minutes and seconds
7562 hours = (int)(mtime / 3600.0f);
7564 mtime -= (3600.0f * (float)hours);
7566 seconds = (int)mtime%60;
7567 minutes = (int)mtime/60;
7569 // print the hour if necessary
7571 sprintf(time_str,XSTR( "%d:", 201),hours);
7572 // if there are less than 10 minutes, print a leading 0
7574 strcpy(tmp,NOX("0"));
7575 strcat(time_str,tmp);
7579 // print the minutes
7581 sprintf(tmp,XSTR( "%d:", 201),minutes);
7582 strcat(time_str,tmp);
7584 sprintf(time_str,XSTR( "%d:", 201),minutes);
7587 // print the seconds
7589 strcpy(tmp,NOX("0"));
7590 strcat(time_str,tmp);
7592 sprintf(tmp,"%d",seconds);
7593 strcat(time_str,tmp);
7596 // Stuff version string in *str.
7597 void get_version_string(char *str)
7600 if ( FS_VERSION_BUILD == 0 ) {
7601 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7603 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7606 #if defined (FS2_DEMO)
7608 #elif defined (OEM_BUILD)
7609 strcat(str, " (OEM)");
7615 char myname[_MAX_PATH];
7616 int namelen, major, minor, build, waste;
7617 unsigned int buf_size;
7623 // Find my EXE file name
7624 hMod = GetModuleHandle(NULL);
7625 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7627 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7628 infop = (char *)malloc(version_size);
7629 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7631 // get the product version
7632 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7633 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7635 sprintf(str,"Dv%d.%02d",major, minor);
7637 sprintf(str,"v%d.%02d",major, minor);
7642 void get_version_string_short(char *str)
7644 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7647 // ----------------------------------------------------------------
7649 // OEM UPSELL SCREENS BEGIN
7651 // ----------------------------------------------------------------
7652 #if defined(OEM_BUILD)
7654 #define NUM_OEM_UPSELL_SCREENS 3
7655 #define OEM_UPSELL_SCREEN_DELAY 10000
7657 static int Oem_upsell_bitmaps_loaded = 0;
7658 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7659 static int Oem_upsell_screen_number = 0;
7660 static int Oem_upsell_show_next_bitmap_time;
7663 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7676 static int Oem_normal_cursor = -1;
7677 static int Oem_web_cursor = -1;
7678 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7679 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7681 void oem_upsell_next_screen()
7683 Oem_upsell_screen_number++;
7684 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7685 // extra long delay, mouse shown on last upsell
7686 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7690 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7694 void oem_upsell_load_bitmaps()
7698 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7699 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7703 void oem_upsell_unload_bitmaps()
7707 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7708 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7709 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7714 Oem_upsell_bitmaps_loaded = 0;
7717 // clickable hotspot on 3rd OEM upsell screen
7718 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7720 28, 350, 287, 96 // x, y, w, h
7723 45, 561, 460, 152 // x, y, w, h
7727 void oem_upsell_show_screens()
7729 int current_time, k;
7732 if ( !Oem_upsell_bitmaps_loaded ) {
7733 oem_upsell_load_bitmaps();
7734 Oem_upsell_bitmaps_loaded = 1;
7737 // may use upsell screens more than once
7738 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7739 Oem_upsell_screen_number = 0;
7745 int nframes; // used to pass, not really needed (should be 1)
7746 Oem_normal_cursor = gr_get_cursor_bitmap();
7747 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7748 Assert(Oem_web_cursor >= 0);
7749 if (Oem_web_cursor < 0) {
7750 Oem_web_cursor = Oem_normal_cursor;
7755 //oem_reset_trailer_timer();
7757 current_time = timer_get_milliseconds();
7762 // advance screen on keypress or timeout
7763 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7764 oem_upsell_next_screen();
7767 // check if we are done
7768 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7769 Oem_upsell_screen_number--;
7772 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7777 // show me the upsell
7778 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7779 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7783 // if this is the 3rd upsell, make it clickable, d00d
7784 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7786 int button_state = mouse_get_pos(&mx, &my);
7787 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])
7788 && (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]) )
7791 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7794 if (button_state & MOUSE_LEFT_BUTTON) {
7796 multi_pxo_url(OEM_UPSELL_URL);
7800 // switch cursor back to normal one
7801 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7806 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7816 oem_upsell_unload_bitmaps();
7818 // switch cursor back to normal one
7819 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7823 #endif // defined(OEM_BUILD)
7824 // ----------------------------------------------------------------
7826 // OEM UPSELL SCREENS END
7828 // ----------------------------------------------------------------
7832 // ----------------------------------------------------------------
7834 // DEMO UPSELL SCREENS BEGIN
7836 // ----------------------------------------------------------------
7840 //#define NUM_DEMO_UPSELL_SCREENS 4
7842 #define NUM_DEMO_UPSELL_SCREENS 2
7843 #define DEMO_UPSELL_SCREEN_DELAY 3000
7845 static int Demo_upsell_bitmaps_loaded = 0;
7846 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7847 static int Demo_upsell_screen_number = 0;
7848 static int Demo_upsell_show_next_bitmap_time;
7851 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7864 void demo_upsell_next_screen()
7866 Demo_upsell_screen_number++;
7867 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7868 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7870 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7874 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7875 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7876 #ifndef HARDWARE_ONLY
7877 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7884 void demo_upsell_load_bitmaps()
7888 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7889 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7893 void demo_upsell_unload_bitmaps()
7897 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7898 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7899 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7904 Demo_upsell_bitmaps_loaded = 0;
7907 void demo_upsell_show_screens()
7909 int current_time, k;
7912 if ( !Demo_upsell_bitmaps_loaded ) {
7913 demo_upsell_load_bitmaps();
7914 Demo_upsell_bitmaps_loaded = 1;
7917 // may use upsell screens more than once
7918 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7919 Demo_upsell_screen_number = 0;
7926 demo_reset_trailer_timer();
7928 current_time = timer_get_milliseconds();
7935 // don't time out, wait for keypress
7937 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7938 demo_upsell_next_screen();
7943 demo_upsell_next_screen();
7946 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7947 Demo_upsell_screen_number--;
7950 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7955 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7956 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7961 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7971 demo_upsell_unload_bitmaps();
7976 // ----------------------------------------------------------------
7978 // DEMO UPSELL SCREENS END
7980 // ----------------------------------------------------------------
7983 // ----------------------------------------------------------------
7985 // Subspace Ambient Sound START
7987 // ----------------------------------------------------------------
7989 static int Subspace_ambient_left_channel = -1;
7990 static int Subspace_ambient_right_channel = -1;
7993 void game_start_subspace_ambient_sound()
7995 if ( Subspace_ambient_left_channel < 0 ) {
7996 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7999 if ( Subspace_ambient_right_channel < 0 ) {
8000 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8004 void game_stop_subspace_ambient_sound()
8006 if ( Subspace_ambient_left_channel >= 0 ) {
8007 snd_stop(Subspace_ambient_left_channel);
8008 Subspace_ambient_left_channel = -1;
8011 if ( Subspace_ambient_right_channel >= 0 ) {
8012 snd_stop(Subspace_ambient_right_channel);
8013 Subspace_ambient_right_channel = -1;
8017 // ----------------------------------------------------------------
8019 // Subspace Ambient Sound END
8021 // ----------------------------------------------------------------
8023 // ----------------------------------------------------------------
8025 // CDROM detection code START
8027 // ----------------------------------------------------------------
8029 #define CD_SIZE_72_MINUTE_MAX (697000000)
8031 uint game_get_cd_used_space(char *path)
8035 char use_path[512] = "";
8036 char sub_path[512] = "";
8037 WIN32_FIND_DATA find;
8040 // recurse through all files and directories
8041 strcpy(use_path, path);
8042 strcat(use_path, "*.*");
8043 find_handle = FindFirstFile(use_path, &find);
8046 if(find_handle == INVALID_HANDLE_VALUE){
8052 // subdirectory. make sure to ignore . and ..
8053 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8055 strcpy(sub_path, path);
8056 strcat(sub_path, find.cFileName);
8057 strcat(sub_path, "\\");
8058 total += game_get_cd_used_space(sub_path);
8060 total += (uint)find.nFileSizeLow;
8062 } while(FindNextFile(find_handle, &find));
8065 FindClose(find_handle);
8077 // if volume_name is non-null, the CD name must match that
8078 int find_freespace_cd(char *volume_name)
8081 char oldpath[MAX_PATH];
8085 int volume_match = 0;
8089 GetCurrentDirectory(MAX_PATH, oldpath);
8091 for (i = 0; i < 26; i++)
8097 path[0] = (char)('A'+i);
8098 if (GetDriveType(path) == DRIVE_CDROM) {
8100 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8101 nprintf(("CD", "CD volume: %s\n", volume));
8103 // check for any CD volume
8104 int volume1_present = 0;
8105 int volume2_present = 0;
8106 int volume3_present = 0;
8108 char full_check[512] = "";
8110 // look for setup.exe
8111 strcpy(full_check, path);
8112 strcat(full_check, "setup.exe");
8113 find_handle = _findfirst(full_check, &find);
8114 if(find_handle != -1){
8115 volume1_present = 1;
8116 _findclose(find_handle);
8119 // look for intro.mve
8120 strcpy(full_check, path);
8121 strcat(full_check, "intro.mve");
8122 find_handle = _findfirst(full_check, &find);
8123 if(find_handle != -1){
8124 volume2_present = 1;
8125 _findclose(find_handle);
8128 // look for endpart1.mve
8129 strcpy(full_check, path);
8130 strcat(full_check, "endpart1.mve");
8131 find_handle = _findfirst(full_check, &find);
8132 if(find_handle != -1){
8133 volume3_present = 1;
8134 _findclose(find_handle);
8137 // see if we have the specific CD we're looking for
8138 if ( volume_name ) {
8140 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8144 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8148 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8152 if ( volume1_present || volume2_present || volume3_present ) {
8157 // 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
8158 if ( volume_match ){
8160 // 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
8161 if(volume2_present || volume3_present) {
8162 // first step - check to make sure its a cdrom
8163 if(GetDriveType(path) != DRIVE_CDROM){
8167 #if !defined(OEM_BUILD)
8168 // oem not on 80 min cds, so dont check tha size
8170 uint used_space = game_get_cd_used_space(path);
8171 if(used_space < CD_SIZE_72_MINUTE_MAX){
8174 #endif // !defined(OEM_BUILD)
8182 #endif // RELEASE_REAL
8188 SetCurrentDirectory(oldpath);
8197 int set_cdrom_path(int drive_num)
8201 if (drive_num < 0) { //no CD
8203 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8206 strcpy(Game_CDROM_dir,""); //set directory
8210 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8226 i = find_freespace_cd();
8228 rval = set_cdrom_path(i);
8232 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8234 nprintf(("CD", "FreeSpace CD not found\n"));
8242 int Last_cd_label_found = 0;
8243 char Last_cd_label[256];
8245 int game_cd_changed()
8252 if ( strlen(Game_CDROM_dir) == 0 ) {
8256 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8258 if ( found != Last_cd_label_found ) {
8259 Last_cd_label_found = found;
8261 mprintf(( "CD '%s' was inserted\n", label ));
8264 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8268 if ( Last_cd_label_found ) {
8269 if ( !stricmp( Last_cd_label, label )) {
8270 //mprintf(( "CD didn't change\n" ));
8272 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8276 // none found before, none found now.
8277 //mprintf(( "still no CD...\n" ));
8281 Last_cd_label_found = found;
8283 strcpy( Last_cd_label, label );
8285 strcpy( Last_cd_label, "" );
8296 // check if _any_ FreeSpace2 CDs are in the drive
8297 // return: 1 => CD now in drive
8298 // 0 => Could not find CD, they refuse to put it in the drive
8299 int game_do_cd_check(char *volume_name)
8301 #if !defined(GAME_CD_CHECK)
8307 int num_attempts = 0;
8308 int refresh_files = 0;
8310 int path_set_ok, popup_rval;
8312 cd_drive_num = find_freespace_cd(volume_name);
8313 path_set_ok = set_cdrom_path(cd_drive_num);
8314 if ( path_set_ok ) {
8316 if ( refresh_files ) {
8328 // no CD found, so prompt user
8329 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8331 if ( popup_rval != 1 ) {
8336 if ( num_attempts++ > 5 ) {
8347 // check if _any_ FreeSpace2 CDs are in the drive
8348 // return: 1 => CD now in drive
8349 // 0 => Could not find CD, they refuse to put it in the drive
8350 int game_do_cd_check_specific(char *volume_name, int cdnum)
8355 int num_attempts = 0;
8356 int refresh_files = 0;
8358 int path_set_ok, popup_rval;
8360 cd_drive_num = find_freespace_cd(volume_name);
8361 path_set_ok = set_cdrom_path(cd_drive_num);
8362 if ( path_set_ok ) {
8364 if ( refresh_files ) {
8375 // no CD found, so prompt user
8376 #if defined(DVD_MESSAGE_HACK)
8377 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8379 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8382 if ( popup_rval != 1 ) {
8387 if ( num_attempts++ > 5 ) {
8397 // only need to do this in RELEASE_REAL
8398 int game_do_cd_mission_check(char *filename)
8404 fs_builtin_mission *m = game_find_builtin_mission(filename);
8406 // check for changed CD
8407 if(game_cd_changed()){
8412 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8416 // not builtin, so do a general check (any FS2 CD will do)
8418 return game_do_cd_check();
8421 // does not have any CD requirement, do a general check
8422 if(strlen(m->cd_volume) <= 0){
8423 return game_do_cd_check();
8427 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8429 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8431 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8434 return game_do_cd_check();
8437 // did we find the cd?
8438 if(find_freespace_cd(m->cd_volume) >= 0){
8442 // make sure the volume exists
8443 int num_attempts = 0;
8444 int refresh_files = 0;
8446 int path_set_ok, popup_rval;
8448 cd_drive_num = find_freespace_cd(m->cd_volume);
8449 path_set_ok = set_cdrom_path(cd_drive_num);
8450 if ( path_set_ok ) {
8452 if ( refresh_files ) {
8459 // no CD found, so prompt user
8460 #if defined(DVD_MESSAGE_HACK)
8461 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8463 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8467 if ( popup_rval != 1 ) {
8472 if ( num_attempts++ > 5 ) {
8484 // ----------------------------------------------------------------
8486 // CDROM detection code END
8488 // ----------------------------------------------------------------
8490 // ----------------------------------------------------------------
8491 // SHIPS TBL VERIFICATION STUFF
8494 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8495 #define NUM_SHIPS_TBL_CHECKSUMS 1
8497 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8498 -463907578, // US - beta 1
8499 1696074201, // FS2 demo
8502 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8503 // -1022810006, // 1.0 FULL
8504 -1254285366 // 1.2 FULL (German)
8507 void verify_ships_tbl()
8511 Game_ships_tbl_valid = 1;
8517 // detect if the packfile exists
8518 CFILE *detect = cfopen("ships.tbl", "rb");
8519 Game_ships_tbl_valid = 0;
8523 Game_ships_tbl_valid = 0;
8527 // get the long checksum of the file
8529 cfseek(detect, 0, SEEK_SET);
8530 cf_chksum_long(detect, &file_checksum);
8534 // now compare the checksum/filesize against known #'s
8535 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8536 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8537 Game_ships_tbl_valid = 1;
8544 DCF(shipspew, "display the checksum for the current ships.tbl")
8547 CFILE *detect = cfopen("ships.tbl", "rb");
8548 // get the long checksum of the file
8550 cfseek(detect, 0, SEEK_SET);
8551 cf_chksum_long(detect, &file_checksum);
8554 dc_printf("%d", file_checksum);
8557 // ----------------------------------------------------------------
8558 // WEAPONS TBL VERIFICATION STUFF
8561 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8562 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8564 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8565 141718090, // US - beta 1
8566 -266420030, // demo 1
8569 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8570 // 399297860, // 1.0 FULL
8571 -553984927 // 1.2 FULL (german)
8574 void verify_weapons_tbl()
8578 Game_weapons_tbl_valid = 1;
8584 // detect if the packfile exists
8585 CFILE *detect = cfopen("weapons.tbl", "rb");
8586 Game_weapons_tbl_valid = 0;
8590 Game_weapons_tbl_valid = 0;
8594 // get the long checksum of the file
8596 cfseek(detect, 0, SEEK_SET);
8597 cf_chksum_long(detect, &file_checksum);
8601 // now compare the checksum/filesize against known #'s
8602 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8603 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8604 Game_weapons_tbl_valid = 1;
8611 DCF(wepspew, "display the checksum for the current weapons.tbl")
8614 CFILE *detect = cfopen("weapons.tbl", "rb");
8615 // get the long checksum of the file
8617 cfseek(detect, 0, SEEK_SET);
8618 cf_chksum_long(detect, &file_checksum);
8621 dc_printf("%d", file_checksum);
8624 // if the game is running using hacked data
8625 int game_hacked_data()
8628 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8636 void display_title_screen()
8638 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8639 ///int title_bitmap;
8642 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8643 if (title_bitmap == -1) {
8648 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8649 extern void d3d_start_frame();
8654 gr_set_bitmap(title_bitmap);
8660 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8661 extern void d3d_stop_frame();
8668 bm_unload(title_bitmap);
8669 #endif // FS2_DEMO || OEM_BUILD
8672 // return true if the game is running with "low memory", which is less than 48MB
8673 bool game_using_low_mem()
8675 if (Use_low_mem == 0) {