2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.8 2002/05/29 02:52:32 theoddone33
11 * Enable OpenGL renderer
13 * Revision 1.7 2002/05/28 08:52:03 relnev
14 * implemented two assembly stubs.
16 * cleaned up a few warnings.
18 * added a little demo hackery to make it progress a little farther.
20 * Revision 1.6 2002/05/28 06:28:20 theoddone33
21 * Filesystem mods, actually reads some data files now
23 * Revision 1.5 2002/05/28 04:07:28 theoddone33
24 * New graphics stubbing arrangement
26 * Revision 1.4 2002/05/27 22:46:52 theoddone33
27 * Remove more undefined symbols
29 * Revision 1.3 2002/05/26 23:31:18 relnev
30 * added a few files that needed to be compiled
32 * freespace.cpp: now compiles
34 * Revision 1.2 2002/05/07 03:16:44 theoddone33
35 * The Great Newline Fix
37 * Revision 1.1.1.1 2002/05/03 03:28:09 root
41 * 201 6/16/00 3:15p Jefff
42 * sim of the year dvd version changes, a few german soty localization
45 * 200 11/03/99 11:06a Jefff
48 * 199 10/26/99 5:07p Jamest
49 * fixed jeffs dumb debug code
51 * 198 10/25/99 5:53p Jefff
52 * call control_config_common_init() on startup
54 * 197 10/14/99 10:18a Daveb
55 * Fixed incorrect CD checking problem on standalone server.
57 * 196 10/13/99 9:22a Daveb
58 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
59 * related to movies. Fixed launcher spawning from PXO screen.
61 * 195 10/06/99 11:05a Jefff
62 * new oem upsell 3 hotspot coords
64 * 194 10/06/99 10:31a Jefff
67 * 193 10/01/99 9:10a Daveb
70 * 192 9/15/99 4:57a Dave
71 * Updated ships.tbl checksum
73 * 191 9/15/99 3:58a Dave
74 * Removed framerate warning at all times.
76 * 190 9/15/99 3:16a Dave
77 * Remove mt-011.fs2 from the builtin mission list.
79 * 189 9/15/99 1:45a Dave
80 * Don't init joystick on standalone. Fixed campaign mode on standalone.
81 * Fixed no-score-report problem in TvT
83 * 188 9/14/99 6:08a Dave
84 * Updated (final) single, multi, and campaign list.
86 * 187 9/14/99 3:26a Dave
87 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
88 * respawn-too-early problem. Made a few crash points safe.
90 * 186 9/13/99 4:52p Dave
93 * 185 9/12/99 8:09p Dave
94 * Fixed problem where skip-training button would cause mission messages
95 * not to get paged out for the current mission.
97 * 184 9/10/99 11:53a Dave
98 * Shutdown graphics before sound to eliminate apparent lockups when
99 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
101 * 183 9/09/99 11:40p Dave
102 * Handle an Assert() in beam code. Added supernova sounds. Play the right
103 * 2 end movies properly, based upon what the player did in the mission.
105 * 182 9/08/99 10:29p Dave
106 * Make beam sound pausing and unpausing much safer.
108 * 181 9/08/99 10:01p Dave
109 * Make sure game won't run in a drive's root directory. Make sure
110 * standalone routes suqad war messages properly to the host.
112 * 180 9/08/99 3:22p Dave
113 * Updated builtin mission list.
115 * 179 9/08/99 12:01p Jefff
116 * fixed Game_builtin_mission_list typo on Training-2.fs2
118 * 178 9/08/99 9:48a Andsager
119 * Add force feedback for engine wash.
121 * 177 9/07/99 4:01p Dave
122 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
123 * does everything properly (setting up address when binding). Remove
124 * black rectangle background from UI_INPUTBOX.
126 * 176 9/13/99 2:40a Dave
127 * Comment in full 80 minute CD check for RELEASE_REAL builds.
129 * 175 9/06/99 6:38p Dave
130 * Improved CD detection code.
132 * 174 9/06/99 1:30a Dave
133 * Intermediate checkin. Started on enforcing CD-in-drive to play the
136 * 173 9/06/99 1:16a Dave
137 * Make sure the user sees the intro movie.
139 * 172 9/04/99 8:00p Dave
140 * Fixed up 1024 and 32 bit movie support.
142 * 171 9/03/99 1:32a Dave
143 * CD checking by act. Added support to play 2 cutscenes in a row
144 * seamlessly. Fixed super low level cfile bug related to files in the
145 * root directory of a CD. Added cheat code to set campaign mission # in
148 * 170 9/01/99 10:49p Dave
149 * Added nice SquadWar checkbox to the client join wait screen.
151 * 169 9/01/99 10:14a Dave
154 * 168 8/29/99 4:51p Dave
155 * Fixed damaged checkin.
157 * 167 8/29/99 4:18p Andsager
158 * New "burst" limit for friendly damage. Also credit more damage done
159 * against large friendly ships.
161 * 166 8/27/99 6:38p Alanl
162 * crush the blasted repeating messages bug
164 * 164 8/26/99 9:09p Dave
165 * Force framerate check in everything but a RELEASE_REAL build.
167 * 163 8/26/99 9:45a Dave
168 * First pass at easter eggs and cheats.
170 * 162 8/24/99 8:55p Dave
171 * Make sure nondimming pixels work properly in tech menu.
173 * 161 8/24/99 1:49a Dave
174 * Fixed client-side afterburner stuttering. Added checkbox for no version
175 * checking on PXO join. Made button info passing more friendly between
178 * 160 8/22/99 5:53p Dave
179 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
180 * instead of ship designations for multiplayer players.
182 * 159 8/22/99 1:19p Dave
183 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
184 * which d3d cards are detected.
186 * 158 8/20/99 2:09p Dave
187 * PXO banner cycling.
189 * 157 8/19/99 10:59a Dave
190 * Packet loss detection.
192 * 156 8/19/99 10:12a Alanl
193 * preload mission-specific messages on machines greater than 48MB
195 * 155 8/16/99 4:04p Dave
196 * Big honking checkin.
198 * 154 8/11/99 5:54p Dave
199 * Fixed collision problem. Fixed standalone ghost problem.
201 * 153 8/10/99 7:59p Jefff
204 * 152 8/10/99 6:54p Dave
205 * Mad optimizations. Added paging to the nebula effect.
207 * 151 8/10/99 3:44p Jefff
208 * loads Intelligence information on startup
210 * 150 8/09/99 3:47p Dave
211 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
212 * non-nebula missions.
214 * 149 8/09/99 2:21p Andsager
215 * Fix patching from multiplayer direct to launcher update tab.
217 * 148 8/09/99 10:36a Dave
218 * Version info for game.
220 * 147 8/06/99 9:46p Dave
221 * Hopefully final changes for the demo.
223 * 146 8/06/99 3:34p Andsager
224 * Make title version info "(D)" -> "D" show up nicely
226 * 145 8/06/99 2:59p Adamp
227 * Fixed NT launcher/update problem.
229 * 144 8/06/99 1:52p Dave
230 * Bumped up MAX_BITMAPS for the demo.
232 * 143 8/06/99 12:17p Andsager
233 * Demo: down to just 1 demo dog
235 * 142 8/05/99 9:39p Dave
236 * Yet another new checksum.
238 * 141 8/05/99 6:19p Dave
239 * New demo checksums.
241 * 140 8/05/99 5:31p Andsager
242 * Up demo version 1.01
244 * 139 8/05/99 4:22p Andsager
245 * No time limit on upsell screens. Reverse order of display of upsell
248 * 138 8/05/99 4:17p Dave
249 * Tweaks to client interpolation.
251 * 137 8/05/99 3:52p Danw
253 * 136 8/05/99 3:01p Danw
255 * 135 8/05/99 2:43a Anoop
256 * removed duplicate definition.
258 * 134 8/05/99 2:13a Dave
261 * 133 8/05/99 2:05a Dave
264 * 132 8/05/99 1:22a Andsager
267 * 131 8/04/99 9:51p Andsager
268 * Add title screen to demo
270 * 130 8/04/99 6:47p Jefff
271 * fixed link error resulting from #ifdefs
273 * 129 8/04/99 6:26p Dave
274 * Updated ship tbl checksum.
276 * 128 8/04/99 5:40p Andsager
277 * Add multiple demo dogs
279 * 127 8/04/99 5:36p Andsager
280 * Show upsell screens at end of demo campaign before returning to main
283 * 126 8/04/99 11:42a Danw
284 * tone down EAX reverb
286 * 125 8/04/99 11:23a Dave
287 * Updated demo checksums.
289 * 124 8/03/99 11:02p Dave
290 * Maybe fixed sync problems in multiplayer.
292 * 123 8/03/99 6:21p Jefff
295 * 122 8/03/99 3:44p Andsager
296 * Launch laucher if trying to run FS without first having configured
299 * 121 8/03/99 12:45p Dave
302 * 120 8/02/99 9:13p Dave
305 * 119 7/30/99 10:31p Dave
306 * Added comm menu to the configurable hud files.
308 * 118 7/30/99 5:17p Andsager
309 * first fs2demo checksums
311 * 117 7/29/99 3:09p Anoop
313 * 116 7/29/99 12:05a Dave
314 * Nebula speed optimizations.
316 * 115 7/27/99 8:59a Andsager
317 * Make major, minor version consistent for all builds. Only show major
318 * and minor for launcher update window.
320 * 114 7/26/99 5:50p Dave
321 * Revised ingame join. Better? We'll see....
323 * 113 7/26/99 5:27p Andsager
324 * Add training mission as builtin to demo build
326 * 112 7/24/99 1:54p Dave
327 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
330 * 111 7/22/99 4:00p Dave
331 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
333 * 110 7/21/99 8:10p Dave
334 * First run of supernova effect.
336 * 109 7/20/99 1:49p Dave
337 * Peter Drake build. Fixed some release build warnings.
339 * 108 7/19/99 2:26p Andsager
340 * set demo multiplayer missions
342 * 107 7/18/99 5:19p Dave
343 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
345 * 106 7/16/99 1:50p Dave
346 * 8 bit aabitmaps. yay.
348 * 105 7/15/99 3:07p Dave
349 * 32 bit detection support. Mouse coord commandline.
351 * 104 7/15/99 2:13p Dave
352 * Added 32 bit detection.
354 * 103 7/15/99 9:20a Andsager
355 * FS2_DEMO initial checkin
357 * 102 7/14/99 11:02a Dave
358 * Skill level default back to easy. Blech.
360 * 101 7/09/99 5:54p Dave
361 * Seperated cruiser types into individual types. Added tons of new
362 * briefing icons. Campaign screen.
364 * 100 7/08/99 4:43p Andsager
365 * New check for sparky_hi and print if not found.
367 * 99 7/08/99 10:53a Dave
368 * New multiplayer interpolation scheme. Not 100% done yet, but still
369 * better than the old way.
371 * 98 7/06/99 4:24p Dave
372 * Mid-level checkin. Starting on some potentially cool multiplayer
375 * 97 7/06/99 3:35p Andsager
376 * Allow movie to play before red alert mission.
378 * 96 7/03/99 5:50p Dave
379 * Make rotated bitmaps draw properly in padlock views.
381 * 95 7/02/99 9:55p Dave
382 * Player engine wash sound.
384 * 94 7/02/99 4:30p Dave
385 * Much more sophisticated lightning support.
387 * 93 6/29/99 7:52p Dave
388 * Put in exception handling in FS2.
390 * 92 6/22/99 9:37p Dave
391 * Put in pof spewing.
393 * 91 6/16/99 4:06p Dave
394 * New pilot info popup. Added new draw-bitmap-as-poly function.
396 * 90 6/15/99 1:56p Andsager
397 * For release builds, allow start up in high res only with
400 * 89 6/15/99 9:34a Dave
401 * Fixed key checking in single threaded version of the stamp notification
404 * 88 6/09/99 2:55p Andsager
405 * Allow multiple asteroid subtypes (of large, medium, small) and follow
408 * 87 6/08/99 1:14a Dave
409 * Multi colored hud test.
411 * 86 6/04/99 9:52a Dave
412 * Fixed some rendering problems.
414 * 85 6/03/99 10:15p Dave
415 * Put in temporary main hall screen.
417 * 84 6/02/99 6:18p Dave
418 * Fixed TNT lockup problems! Wheeeee!
420 * 83 6/01/99 3:52p Dave
421 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
422 * dead popup, pxo find player popup, pxo private room popup.
424 * 82 5/26/99 1:28p Jasenw
425 * changed coords for loading ani
427 * 81 5/26/99 11:46a Dave
428 * Added ship-blasting lighting and made the randomization of lighting
429 * much more customizable.
431 * 80 5/24/99 5:45p Dave
432 * Added detail levels to the nebula, with a decent speedup. Split nebula
433 * lightning into its own section.
451 #include "systemvars.h"
456 #include "starfield.h"
457 #include "lighting.h"
462 #include "fireballs.h"
466 #include "floating.h"
467 #include "gamesequence.h"
469 #include "optionsmenu.h"
470 #include "playermenu.h"
471 #include "trainingmenu.h"
472 #include "techmenu.h"
475 #include "hudmessage.h"
477 #include "missiongoals.h"
478 #include "missionparse.h"
483 #include "multiutil.h"
484 #include "multimsgs.h"
488 #include "freespace.h"
489 #include "managepilot.h"
491 #include "contexthelp.h"
494 #include "missionbrief.h"
495 #include "missiondebrief.h"
497 #include "missionshipchoice.h"
499 #include "hudconfig.h"
500 #include "controlsconfig.h"
501 #include "missionmessage.h"
502 #include "missiontraining.h"
504 #include "hudtarget.h"
508 #include "eventmusic.h"
509 #include "animplay.h"
510 #include "missionweaponchoice.h"
511 #include "missionlog.h"
512 #include "audiostr.h"
514 #include "missioncampaign.h"
516 #include "missionhotkey.h"
517 #include "objectsnd.h"
518 #include "cmeasure.h"
520 #include "linklist.h"
521 #include "shockwave.h"
522 #include "afterburner.h"
527 #include "stand_gui.h"
528 #include "pcxutils.h"
529 #include "hudtargetbox.h"
530 #include "multi_xfer.h"
531 #include "hudescort.h"
532 #include "multiutil.h"
535 #include "multiteamselect.h"
538 #include "readyroom.h"
539 #include "mainhallmenu.h"
540 #include "multilag.h"
542 #include "particle.h"
544 #include "multi_ingame.h"
545 #include "snazzyui.h"
546 #include "asteroid.h"
547 #include "popupdead.h"
548 #include "multi_voice.h"
549 #include "missioncmdbrief.h"
550 #include "redalert.h"
551 #include "gameplayhelp.h"
552 #include "multilag.h"
553 #include "staticrand.h"
554 #include "multi_pmsg.h"
555 #include "levelpaging.h"
556 #include "observer.h"
557 #include "multi_pause.h"
558 #include "multi_endgame.h"
559 #include "cutscenes.h"
560 #include "multi_respawn.h"
561 // #include "movie.h"
562 #include "multi_obj.h"
563 #include "multi_log.h"
565 #include "localize.h"
566 #include "osregistry.h"
567 #include "barracks.h"
568 #include "missionpause.h"
570 #include "alphacolors.h"
571 #include "objcollide.h"
574 #include "neblightning.h"
575 #include "shipcontrails.h"
578 #include "multi_dogfight.h"
579 #include "multi_rate.h"
580 #include "muzzleflash.h"
584 #include "mainhalltemp.h"
585 #include "exceptionhandler.h"
589 #include "supernova.h"
590 #include "hudshield.h"
591 // #include "names.h"
593 #include "missionloopbrief.h"
597 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
603 // 1.00.04 5/26/98 MWA -- going final (12 pm)
604 // 1.00.03 5/26/98 MWA -- going final (3 am)
605 // 1.00.02 5/25/98 MWA -- going final
606 // 1.00.01 5/25/98 MWA -- going final
607 // 0.90 5/21/98 MWA -- getting ready for final.
608 // 0.10 4/9/98. Set by MK.
610 // Demo version: (obsolete since DEMO codebase split from tree)
611 // 0.03 4/10/98 AL. Interplay rev
612 // 0.02 4/8/98 MK. Increased when this system was modified.
613 // 0.01 4/7/98? AL. First release to Interplay QA.
616 // 1.00 5/28/98 AL. First release to Interplay QA.
618 void game_level_init(int seed = -1);
619 void game_post_level_init();
620 void game_do_frame();
621 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
622 void game_reset_time();
623 void game_show_framerate(); // draws framerate in lower right corner
625 int Game_no_clear = 0;
627 int Pofview_running = 0;
628 int Nebedit_running = 0;
630 typedef struct big_expl_flash {
631 float max_flash_intensity; // max intensity
632 float cur_flash_intensity; // cur intensity
633 int flash_start; // start time
636 #define FRAME_FILTER 16
638 #define DEFAULT_SKILL_LEVEL 1
639 int Game_skill_level = DEFAULT_SKILL_LEVEL;
641 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
642 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
644 #define EXE_FNAME ("fs2.exe")
645 #define LAUNCHER_FNAME ("freespace2.exe")
647 // JAS: Code for warphole camera.
648 // Needs to be cleaned up.
649 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
650 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
651 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
652 matrix Camera_orient = IDENTITY_MATRIX;
653 float Camera_damping = 1.0f;
654 float Camera_time = 0.0f;
655 float Warpout_time = 0.0f;
656 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
657 int Warpout_sound = -1;
659 int Use_joy_mouse = 0;
660 int Use_palette_flash = 1;
662 int Use_fullscreen_at_startup = 0;
664 int Show_area_effect = 0;
665 object *Last_view_target = NULL;
667 int dogfight_blown = 0;
670 float frametimes[FRAME_FILTER];
671 float frametotal = 0.0f;
675 int Show_framerate = 0;
677 int Show_framerate = 1;
680 int Framerate_cap = 120;
683 int Show_target_debug_info = 0;
684 int Show_target_weapons = 0;
686 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
688 int Debug_octant = -1;
690 fix Game_time_compression = F1_0;
692 // if the ships.tbl the player has is valid
693 int Game_ships_tbl_valid = 0;
695 // if the weapons.tbl the player has is valid
696 int Game_weapons_tbl_valid = 0;
700 extern int Player_attacking_enabled;
704 int Pre_player_entry;
706 int Fred_running = 0;
707 char Game_current_mission_filename[MAX_FILENAME_LEN];
708 int game_single_step = 0;
709 int last_single_step=0;
711 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
712 extern int MSG_WINDOW_Y_START;
713 extern int MSG_WINDOW_HEIGHT;
715 int game_zbuffer = 1;
716 //static int Game_music_paused;
717 static int Game_paused;
721 #define EXPIRE_BAD_CHECKSUM 1
722 #define EXPIRE_BAD_TIME 2
724 extern void ssm_init();
725 extern void ssm_level_init();
726 extern void ssm_process();
728 // static variable to contain the time this version was built
729 // commented out for now until
730 // I figure out how to get the username into the file
731 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
733 // defines and variables used for dumping frame for making trailers.
735 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
736 int Debug_dump_trigger = 0;
737 int Debug_dump_frame_count;
738 int Debug_dump_frame_num = 0;
739 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
742 // amount of time to wait after the player has died before we display the death died popup
743 #define PLAYER_DIED_POPUP_WAIT 2500
744 int Player_died_popup_wait = -1;
745 int Player_multi_died_check = -1;
747 // builtin mission list stuff
749 int Game_builtin_mission_count = 6;
750 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
751 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
752 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
753 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
754 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
755 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
756 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
758 #elif defined(PD_BUILD)
759 int Game_builtin_mission_count = 4;
760 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
761 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
762 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
763 { "sm1-01", (FSB_FROM_VOLITION), "" },
764 { "sm1-05", (FSB_FROM_VOLITION), "" },
766 #elif defined(MULTIPLAYER_BETA)
767 int Game_builtin_mission_count = 17;
768 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
770 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
771 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
772 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
773 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
774 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
775 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
776 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
777 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
778 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
779 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
780 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
781 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
782 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
783 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
784 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
785 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
786 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
788 #elif defined(OEM_BUILD)
789 int Game_builtin_mission_count = 17;
790 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
791 // oem version - act 1 only
792 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
795 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
796 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
797 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
798 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
799 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
800 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
801 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
802 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
803 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
804 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
805 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
806 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
807 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
808 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
809 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
810 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
813 int Game_builtin_mission_count = 92;
814 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
815 // single player campaign
816 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
819 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
820 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
822 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
823 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
825 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
826 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
827 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
828 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
829 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
830 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
831 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
832 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
833 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
834 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
835 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
836 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
837 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
840 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
841 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
847 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
848 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
853 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
854 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
856 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
857 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
858 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
859 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
860 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
861 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
862 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
863 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
865 // multiplayer missions
868 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
909 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
910 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
912 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
913 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
914 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
915 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
916 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
917 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
918 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
921 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
922 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
923 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
924 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
925 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
930 // Internal function prototypes
931 void game_maybe_draw_mouse(float frametime);
932 void init_animating_pointer();
933 void load_animating_pointer(char *filename, int dx, int dy);
934 void unload_animating_pointer();
935 void game_do_training_checks();
936 void game_shutdown(void);
937 void game_show_event_debug(float frametime);
938 void game_event_debug_init();
940 void demo_upsell_show_screens();
941 void game_start_subspace_ambient_sound();
942 void game_stop_subspace_ambient_sound();
943 void verify_ships_tbl();
944 void verify_weapons_tbl();
945 void display_title_screen();
947 // loading background filenames
948 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
949 "LoadingBG", // GR_640
950 "2_LoadingBG" // GR_1024
954 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
955 "Loading.ani", // GR_640
956 "2_Loading.ani" // GR_1024
959 #if defined(FS2_DEMO)
960 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
964 #elif defined(OEM_BUILD)
965 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
972 char Game_CDROM_dir[MAX_PATH_LEN];
975 // How much RAM is on this machine. Set in WinMain
976 uint Freespace_total_ram = 0;
979 float Game_flash_red = 0.0f;
980 float Game_flash_green = 0.0f;
981 float Game_flash_blue = 0.0f;
982 float Sun_spot = 0.0f;
983 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
985 // game shudder stuff (in ms)
986 int Game_shudder_time = -1;
987 int Game_shudder_total = 0;
988 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
991 sound_env Game_sound_env;
992 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
993 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
995 int Game_sound_env_update_timestamp;
997 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1000 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1002 fs_builtin_mission *game_find_builtin_mission(char *filename)
1006 // look through all existing builtin missions
1007 for(idx=0; idx<Game_builtin_mission_count; idx++){
1008 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1009 return &Game_builtin_mission_list[idx];
1017 int game_get_default_skill_level()
1019 return DEFAULT_SKILL_LEVEL;
1023 void game_flash_reset()
1025 Game_flash_red = 0.0f;
1026 Game_flash_green = 0.0f;
1027 Game_flash_blue = 0.0f;
1029 Big_expl_flash.max_flash_intensity = 0.0f;
1030 Big_expl_flash.cur_flash_intensity = 0.0f;
1031 Big_expl_flash.flash_start = 0;
1034 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1035 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1037 void game_framerate_check_init()
1039 // zero critical time
1040 Gf_critical_time = 0.0f;
1043 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1044 // if this is a glide card
1045 if(gr_screen.mode == GR_GLIDE){
1047 extern GrHwConfiguration hwconfig;
1050 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1051 Gf_critical = 15.0f;
1055 Gf_critical = 10.0f;
1060 Gf_critical = 15.0f;
1063 // d3d. only care about good cards here I guess (TNT)
1065 Gf_critical = 15.0f;
1068 // if this is a glide card
1069 if(gr_screen.mode == GR_GLIDE){
1071 extern GrHwConfiguration hwconfig;
1074 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1075 Gf_critical = 25.0f;
1079 Gf_critical = 20.0f;
1084 Gf_critical = 25.0f;
1087 // d3d. only care about good cards here I guess (TNT)
1089 Gf_critical = 25.0f;
1094 extern float Framerate;
1095 void game_framerate_check()
1099 // if the current framerate is above the critical level, add frametime
1100 if(Framerate >= Gf_critical){
1101 Gf_critical_time += flFrametime;
1104 if(!Show_framerate){
1108 // display if we're above the critical framerate
1109 if(Framerate < Gf_critical){
1110 gr_set_color_fast(&Color_bright_red);
1111 gr_string(200, y_start, "Framerate warning");
1116 // display our current pct of good frametime
1117 if(f2fl(Missiontime) >= 0.0f){
1118 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1121 gr_set_color_fast(&Color_bright_green);
1123 gr_set_color_fast(&Color_bright_red);
1126 gr_printf(200, y_start, "%d%%", (int)pct);
1133 // Adds a flash effect. These can be positive or negative.
1134 // The range will get capped at around -1 to 1, so stick
1135 // with a range like that.
1136 void game_flash( float r, float g, float b )
1138 Game_flash_red += r;
1139 Game_flash_green += g;
1140 Game_flash_blue += b;
1142 if ( Game_flash_red < -1.0f ) {
1143 Game_flash_red = -1.0f;
1144 } else if ( Game_flash_red > 1.0f ) {
1145 Game_flash_red = 1.0f;
1148 if ( Game_flash_green < -1.0f ) {
1149 Game_flash_green = -1.0f;
1150 } else if ( Game_flash_green > 1.0f ) {
1151 Game_flash_green = 1.0f;
1154 if ( Game_flash_blue < -1.0f ) {
1155 Game_flash_blue = -1.0f;
1156 } else if ( Game_flash_blue > 1.0f ) {
1157 Game_flash_blue = 1.0f;
1162 // Adds a flash for Big Ship explosions
1163 // cap range from 0 to 1
1164 void big_explosion_flash(float flash)
1166 Big_expl_flash.flash_start = timestamp(1);
1170 } else if (flash < 0.0f) {
1174 Big_expl_flash.max_flash_intensity = flash;
1175 Big_expl_flash.cur_flash_intensity = 0.0f;
1178 // Amount to diminish palette towards normal, per second.
1179 #define DIMINISH_RATE 0.75f
1180 #define SUN_DIMINISH_RATE 6.00f
1184 float sn_glare_scale = 1.7f;
1187 dc_get_arg(ARG_FLOAT);
1188 sn_glare_scale = Dc_arg_float;
1191 float Supernova_last_glare = 0.0f;
1192 void game_sunspot_process(float frametime)
1196 float Sun_spot_goal = 0.0f;
1199 sn_stage = supernova_active();
1201 // sunspot differently based on supernova stage
1203 // approaching. player still in control
1206 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1209 light_get_global_dir(&light_dir, 0);
1211 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1214 // scale it some more
1215 dot = dot * (0.5f + (pct * 0.5f));
1218 Sun_spot_goal += (dot * sn_glare_scale);
1221 // draw the sun glow
1222 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1223 // draw the glow for this sun
1224 stars_draw_sun_glow(0);
1227 Supernova_last_glare = Sun_spot_goal;
1230 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1233 Sun_spot_goal = 0.9f;
1234 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1236 if(Sun_spot_goal > 1.0f){
1237 Sun_spot_goal = 1.0f;
1240 Sun_spot_goal *= sn_glare_scale;
1241 Supernova_last_glare = Sun_spot_goal;
1244 // fade to white. display dead popup
1247 Supernova_last_glare += (2.0f * flFrametime);
1248 if(Supernova_last_glare > 2.0f){
1249 Supernova_last_glare = 2.0f;
1252 Sun_spot_goal = Supernova_last_glare;
1259 // check sunspots for all suns
1260 n_lights = light_get_global_count();
1263 for(idx=0; idx<n_lights; idx++){
1264 //(vector *eye_pos, matrix *eye_orient)
1265 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1268 light_get_global_dir(&light_dir, idx);
1270 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1272 Sun_spot_goal += (float)pow(dot,85.0f);
1274 // draw the glow for this sun
1275 stars_draw_sun_glow(idx);
1277 Sun_spot_goal = 0.0f;
1283 Sun_spot_goal = 0.0f;
1287 float dec_amount = frametime*SUN_DIMINISH_RATE;
1289 if ( Sun_spot < Sun_spot_goal ) {
1290 Sun_spot += dec_amount;
1291 if ( Sun_spot > Sun_spot_goal ) {
1292 Sun_spot = Sun_spot_goal;
1294 } else if ( Sun_spot > Sun_spot_goal ) {
1295 Sun_spot -= dec_amount;
1296 if ( Sun_spot < Sun_spot_goal ) {
1297 Sun_spot = Sun_spot_goal;
1303 // Call once a frame to diminish the
1304 // flash effect to 0.
1305 void game_flash_diminish(float frametime)
1307 float dec_amount = frametime*DIMINISH_RATE;
1309 if ( Game_flash_red > 0.0f ) {
1310 Game_flash_red -= dec_amount;
1311 if ( Game_flash_red < 0.0f )
1312 Game_flash_red = 0.0f;
1314 Game_flash_red += dec_amount;
1315 if ( Game_flash_red > 0.0f )
1316 Game_flash_red = 0.0f;
1319 if ( Game_flash_green > 0.0f ) {
1320 Game_flash_green -= dec_amount;
1321 if ( Game_flash_green < 0.0f )
1322 Game_flash_green = 0.0f;
1324 Game_flash_green += dec_amount;
1325 if ( Game_flash_green > 0.0f )
1326 Game_flash_green = 0.0f;
1329 if ( Game_flash_blue > 0.0f ) {
1330 Game_flash_blue -= dec_amount;
1331 if ( Game_flash_blue < 0.0f )
1332 Game_flash_blue = 0.0f;
1334 Game_flash_blue += dec_amount;
1335 if ( Game_flash_blue > 0.0f )
1336 Game_flash_blue = 0.0f;
1339 // update big_explosion_cur_flash
1340 #define TIME_UP 1500
1341 #define TIME_DOWN 2500
1342 int duration = TIME_UP + TIME_DOWN;
1343 int time = timestamp_until(Big_expl_flash.flash_start);
1344 if (time > -duration) {
1346 if (time < TIME_UP) {
1347 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1350 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1354 if ( Use_palette_flash ) {
1356 // static int or=0, og=0, ob=0;
1358 // Change the 200 to change the color range of colors.
1359 r = fl2i( Game_flash_red*128.0f );
1360 g = fl2i( Game_flash_green*128.0f );
1361 b = fl2i( Game_flash_blue*128.0f );
1363 if ( Sun_spot > 0.0f ) {
1364 r += fl2i(Sun_spot*128.0f);
1365 g += fl2i(Sun_spot*128.0f);
1366 b += fl2i(Sun_spot*128.0f);
1369 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1370 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1371 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1372 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1375 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1376 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1377 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1379 if ( (r!=0) || (g!=0) || (b!=0) ) {
1380 gr_flash( r, g, b );
1382 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1393 void game_level_close()
1395 // De-Initialize the game subsystems
1396 message_mission_shutdown();
1397 event_music_level_close();
1398 game_stop_looped_sounds();
1400 obj_snd_level_close(); // uninit object-linked persistant sounds
1401 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1402 anim_level_close(); // stop and clean up any anim instances
1403 shockwave_level_close();
1404 fireball_level_close();
1406 mission_event_shutdown();
1407 asteroid_level_close();
1408 model_cache_reset(); // Reset/free all the model caching stuff
1409 flak_level_close(); // unload flak stuff
1410 neb2_level_close(); // shutdown gaseous nebula stuff
1413 mflash_level_close();
1415 audiostream_unpause_all();
1420 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1421 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1422 void game_level_init(int seed)
1424 // seed the random number generator
1426 // if no seed was passed, seed the generator either from the time value, or from the
1427 // netgame security flags -- ensures that all players in multiplayer game will have the
1428 // same randon number sequence (with static rand functions)
1429 if ( Game_mode & GM_NORMAL ) {
1430 Game_level_seed = time(NULL);
1432 Game_level_seed = Netgame.security;
1435 // mwa 9/17/98 -- maybe this assert isn't needed????
1436 Assert( !(Game_mode & GM_MULTIPLAYER) );
1437 Game_level_seed = seed;
1439 srand( Game_level_seed );
1441 // semirand function needs to get re-initted every time in multiplayer
1442 if ( Game_mode & GM_MULTIPLAYER ){
1448 Key_normal_game = (Game_mode & GM_NORMAL);
1451 Game_shudder_time = -1;
1453 // Initialize the game subsystems
1454 // timestamp_reset(); // Must be inited before everything else
1456 game_reset_time(); // resets time, and resets saved time too
1458 obj_init(); // Must be inited before the other systems
1459 model_free_all(); // Free all existing models
1460 mission_brief_common_init(); // Free all existing briefing/debriefing text
1461 weapon_level_init();
1462 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1464 player_level_init();
1465 shipfx_flash_init(); // Init the ship gun flash system.
1466 game_flash_reset(); // Reset the flash effect
1467 particle_init(); // Reset the particle system
1471 shield_hit_init(); // Initialize system for showing shield hits
1472 radar_mission_init();
1473 mission_init_goals();
1476 obj_snd_level_init(); // init object-linked persistant sounds
1478 shockwave_level_init();
1479 afterburner_level_init();
1480 scoring_level_init( &Player->stats );
1482 asteroid_level_init();
1483 control_config_clear_used_status();
1484 collide_ship_ship_sounds_init();
1486 Pre_player_entry = 1; // Means the player has not yet entered.
1487 Entry_delay_time = 0; // Could get overwritten in mission read.
1488 fireball_preload(); // page in warphole bitmaps
1490 flak_level_init(); // initialize flak - bitmaps, etc
1491 ct_level_init(); // initialize ships contrails, etc
1492 awacs_level_init(); // initialize AWACS
1493 beam_level_init(); // initialize beam weapons
1494 mflash_level_init();
1496 supernova_level_init();
1498 // multiplayer dogfight hack
1501 shipfx_engine_wash_level_init();
1505 Last_view_target = NULL;
1510 // campaign wasn't ended
1511 Campaign_ended_in_mission = 0;
1514 // called when a mission is over -- does server specific stuff.
1515 void freespace_stop_mission()
1518 Game_mode &= ~GM_IN_MISSION;
1521 // called at frame interval to process networking stuff
1522 void game_do_networking()
1524 Assert( Net_player != NULL );
1525 if (!(Game_mode & GM_MULTIPLAYER)){
1529 // see if this player should be reading/writing data. Bit is set when at join
1530 // screen onward until quits back to main menu.
1531 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1535 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1538 multi_pause_do_frame();
1543 // Loads the best palette for this level, based
1544 // on nebula color and hud color. You could just call palette_load_table with
1545 // the appropriate filename, but who wants to do that.
1546 void game_load_palette()
1548 char palette_filename[1024];
1550 // We only use 3 hud colors right now
1551 // Assert( HUD_config.color >= 0 );
1552 // Assert( HUD_config.color <= 2 );
1554 Assert( Mission_palette >= 0 );
1555 Assert( Mission_palette <= 98 );
1557 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1558 strcpy( palette_filename, NOX("gamepalette-subspace") );
1560 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1563 mprintf(( "Loading palette %s\n", palette_filename ));
1565 // palette_load_table(palette_filename);
1568 void game_post_level_init()
1570 // Stuff which gets called after mission is loaded. Because player isn't created until
1571 // after mission loads, some things must get initted after the level loads
1573 model_level_post_init();
1576 hud_setup_escort_list();
1577 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1583 game_event_debug_init();
1586 training_mission_init();
1587 asteroid_create_all();
1589 game_framerate_check_init();
1593 // An estimate as to how high the count passed to game_loading_callback will go.
1594 // This is just a guess, it seems to always be about the same. The count is
1595 // proportional to the code being executed, not the time, so this works good
1596 // for a bar, assuming the code does about the same thing each time you
1597 // load a level. You can find this value by looking at the return value
1598 // of game_busy_callback(NULL), which I conveniently print out to the
1599 // debug output window with the '=== ENDING LOAD ==' stuff.
1600 //#define COUNT_ESTIMATE 3706
1601 #define COUNT_ESTIMATE 1111
1603 int Game_loading_callback_inited = 0;
1605 int Game_loading_background = -1;
1606 anim * Game_loading_ani = NULL;
1607 anim_instance *Game_loading_ani_instance;
1608 int Game_loading_frame=-1;
1610 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1619 // This gets called 10x per second and count is the number of times
1620 // game_busy() has been called since the current callback function
1622 void game_loading_callback(int count)
1624 game_do_networking();
1626 Assert( Game_loading_callback_inited==1 );
1627 Assert( Game_loading_ani != NULL );
1629 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1630 if ( framenum > Game_loading_ani->total_frames-1 ) {
1631 framenum = Game_loading_ani->total_frames-1;
1632 } else if ( framenum < 0 ) {
1637 while ( Game_loading_frame < framenum ) {
1638 Game_loading_frame++;
1639 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1643 if ( cbitmap > -1 ) {
1644 if ( Game_loading_background > -1 ) {
1645 gr_set_bitmap( Game_loading_background );
1649 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1650 gr_set_bitmap( cbitmap );
1651 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1653 bm_release(cbitmap);
1659 void game_loading_callback_init()
1661 Assert( Game_loading_callback_inited==0 );
1663 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1664 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1667 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1668 Assert( Game_loading_ani != NULL );
1669 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1670 Assert( Game_loading_ani_instance != NULL );
1671 Game_loading_frame = -1;
1673 Game_loading_callback_inited = 1;
1675 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1680 void game_loading_callback_close()
1682 Assert( Game_loading_callback_inited==1 );
1684 // Make sure bar shows all the way over.
1685 game_loading_callback(COUNT_ESTIMATE);
1687 int real_count = game_busy_callback( NULL );
1690 Game_loading_callback_inited = 0;
1693 mprintf(( "=================== ENDING LOAD ================\n" ));
1694 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1695 mprintf(( "================================================\n" ));
1697 // to remove warnings in release build
1701 free_anim_instance(Game_loading_ani_instance);
1702 Game_loading_ani_instance = NULL;
1703 anim_free(Game_loading_ani);
1704 Game_loading_ani = NULL;
1706 bm_release( Game_loading_background );
1707 common_free_interface_palette(); // restore game palette
1708 Game_loading_background = -1;
1710 gr_set_font( FONT1 );
1713 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1715 void game_maybe_update_sound_environment()
1717 // do nothing for now
1720 // Assign the sound environment for the game, based on the current mission
1722 void game_assign_sound_environment()
1725 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1726 Game_sound_env.id = SND_ENV_DRUGGED;
1727 Game_sound_env.volume = 0.800f;
1728 Game_sound_env.damping = 1.188f;
1729 Game_sound_env.decay = 6.392f;
1731 } else if (Num_asteroids > 30) {
1732 Game_sound_env.id = SND_ENV_AUDITORIUM;
1733 Game_sound_env.volume = 0.603f;
1734 Game_sound_env.damping = 0.5f;
1735 Game_sound_env.decay = 4.279f;
1738 Game_sound_env = Game_default_sound_env;
1742 Game_sound_env = Game_default_sound_env;
1743 Game_sound_env_update_timestamp = timestamp(1);
1746 // function which gets called before actually entering the mission. It is broken down into a funciton
1747 // since it will get called in one place from a single player game and from another place for
1748 // a multiplayer game
1749 void freespace_mission_load_stuff()
1751 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1752 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1753 if(!(Game_mode & GM_STANDALONE_SERVER)){
1755 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1757 game_loading_callback_init();
1759 event_music_level_init(); // preloads the first 2 seconds for each event music track
1762 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1765 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1768 ship_assign_sound_all(); // assign engine sounds to ships
1769 game_assign_sound_environment(); // assign the sound environment for this mission
1772 // call function in missionparse.cpp to fixup player/ai stuff.
1773 mission_parse_fixup_players();
1776 // Load in all the bitmaps for this level
1781 game_loading_callback_close();
1783 // the only thing we need to call on the standalone for now.
1785 // call function in missionparse.cpp to fixup player/ai stuff.
1786 mission_parse_fixup_players();
1788 // Load in all the bitmaps for this level
1794 uint load_mission_load;
1795 uint load_post_level_init;
1796 uint load_mission_stuff;
1798 // tells the server to load the mission and initialize structures
1799 int game_start_mission()
1801 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1803 load_gl_init = time(NULL);
1805 load_gl_init = time(NULL) - load_gl_init;
1807 if (Game_mode & GM_MULTIPLAYER) {
1808 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1810 // clear multiplayer stats
1811 init_multiplayer_stats();
1814 load_mission_load = time(NULL);
1815 if (mission_load()) {
1816 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1817 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1818 gameseq_post_event(GS_EVENT_MAIN_MENU);
1820 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1825 load_mission_load = time(NULL) - load_mission_load;
1827 // If this is a red alert mission in campaign mode, bash wingman status
1828 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1829 red_alert_bash_wingman_status();
1832 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1833 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1834 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1835 // game_load_palette();
1838 load_post_level_init = time(NULL);
1839 game_post_level_init();
1840 load_post_level_init = time(NULL) - load_post_level_init;
1844 void Do_model_timings_test();
1845 Do_model_timings_test();
1849 load_mission_stuff = time(NULL);
1850 freespace_mission_load_stuff();
1851 load_mission_stuff = time(NULL) - load_mission_stuff;
1856 int Interface_framerate = 0;
1859 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1860 DCF_BOOL( show_framerate, Show_framerate )
1861 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1862 DCF_BOOL( show_target_weapons, Show_target_weapons )
1863 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1864 DCF_BOOL( sound, Sound_enabled )
1865 DCF_BOOL( zbuffer, game_zbuffer )
1866 DCF_BOOL( shield_system, New_shield_system )
1867 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1868 DCF_BOOL( player_attacking, Player_attacking_enabled )
1869 DCF_BOOL( show_waypoints, Show_waypoints )
1870 DCF_BOOL( show_area_effect, Show_area_effect )
1871 DCF_BOOL( show_net_stats, Show_net_stats )
1872 DCF_BOOL( log, Log_debug_output_to_file )
1873 DCF_BOOL( training_msg_method, Training_msg_method )
1874 DCF_BOOL( show_player_pos, Show_player_pos )
1875 DCF_BOOL(i_framerate, Interface_framerate )
1877 DCF(show_mem,"Toggles showing mem usage")
1880 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1881 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1882 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1883 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1889 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1891 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1892 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1896 DCF(show_cpu,"Toggles showing cpu usage")
1899 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1900 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1901 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1902 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1908 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1910 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1911 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1918 // AL 4-8-98: always allow players to display their framerate
1921 DCF_BOOL( show_framerate, Show_framerate )
1928 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1931 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1932 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1933 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1934 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1936 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" );
1937 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1939 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1942 DCF(palette_flash,"Toggles palette flash effect on/off")
1945 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1946 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1947 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1948 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1950 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1951 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1954 int Use_low_mem = 0;
1956 DCF(low_mem,"Uses low memory settings regardless of RAM")
1959 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1960 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1961 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1962 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1964 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1965 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1967 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1973 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1976 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1977 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1978 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1979 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1981 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1982 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1983 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1987 int Framerate_delay = 0;
1989 float Freespace_gamma = 1.0f;
1991 DCF(gamma,"Sets Gamma factor")
1994 dc_get_arg(ARG_FLOAT|ARG_NONE);
1995 if ( Dc_arg_type & ARG_FLOAT ) {
1996 Freespace_gamma = Dc_arg_float;
1998 dc_printf( "Gamma reset to 1.0f\n" );
1999 Freespace_gamma = 1.0f;
2001 if ( Freespace_gamma < 0.1f ) {
2002 Freespace_gamma = 0.1f;
2003 } else if ( Freespace_gamma > 5.0f ) {
2004 Freespace_gamma = 5.0f;
2006 gr_set_gamma(Freespace_gamma);
2008 char tmp_gamma_string[32];
2009 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2010 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2014 dc_printf( "Usage: gamma <float>\n" );
2015 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2016 Dc_status = 0; // don't print status if help is printed. Too messy.
2020 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2029 Game_current_mission_filename[0] = 0;
2031 // seed the random number generator
2032 Game_init_seed = time(NULL);
2033 srand( Game_init_seed );
2035 Framerate_delay = 0;
2041 extern void bm_init();
2047 // Initialize the timer before the os
2055 GetCurrentDirectory(1024, whee);
2058 getcwd (whee, 1024);
2061 strcat(whee, EXE_FNAME);
2063 //Initialize the libraries
2064 s1 = timer_get_milliseconds();
2065 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2068 e1 = timer_get_milliseconds();
2070 // time a bunch of cfopens
2072 s2 = timer_get_milliseconds();
2074 for(int idx=0; idx<10000; idx++){
2075 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2080 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2082 e2 = timer_get_milliseconds();
2085 if (Is_standalone) {
2086 std_init_standalone();
2088 os_init( Osreg_class_name, Osreg_app_name );
2089 os_set_title(Osreg_title);
2092 // initialize localization module. Make sure this is down AFTER initialzing OS.
2093 // int t1 = timer_get_milliseconds();
2096 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2098 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2101 // verify that he has a valid weapons.tbl
2102 verify_weapons_tbl();
2104 // Output version numbers to registry for auto patching purposes
2105 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2106 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2107 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2109 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2110 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2111 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2114 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2118 Asteroids_enabled = 1;
2121 /////////////////////////////
2123 /////////////////////////////
2128 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2129 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2131 if (!stricmp(ptr, NOX("no sound"))) {
2132 Cmdline_freespace_no_sound = 1;
2134 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2136 } else if (!stricmp(ptr, NOX("EAX"))) {
2141 if (!Is_standalone) {
2142 snd_init(use_a3d, use_eax);
2144 /////////////////////////////
2146 /////////////////////////////
2148 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2151 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);
2153 // fire up the UpdateLauncher executable
2155 PROCESS_INFORMATION pi;
2157 memset( &si, 0, sizeof(STARTUPINFO) );
2160 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2161 NULL, // pointer to command line string
2162 NULL, // pointer to process security attributes
2163 NULL, // pointer to thread security attributes
2164 FALSE, // handle inheritance flag
2165 CREATE_DEFAULT_ERROR_MODE, // creation flags
2166 NULL, // pointer to new environment block
2167 NULL, // pointer to current directory name
2168 &si, // pointer to STARTUPINFO
2169 &pi // pointer to PROCESS_INFORMATION
2172 // If the Launcher could not be started up, let the user know
2174 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2183 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2185 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);
2193 // check for hi res pack file
2194 int has_sparky_hi = 0;
2196 // check if sparky_hi exists -- access mode 0 means does file exist
2199 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2202 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2205 // see if we've got 32 bit in the string
2206 if(strstr(ptr, "32 bit")){
2212 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2214 // always 640 for E3
2215 gr_init(GR_640, GR_GLIDE);
2217 // regular or hi-res ?
2219 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2221 if(strstr(ptr, NOX("(1024x768)"))){
2223 gr_init(GR_1024, GR_GLIDE);
2225 gr_init(GR_640, GR_GLIDE);
2228 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2230 // always 640 for E3
2232 gr_init(GR_640, GR_DIRECT3D, depth);
2234 // regular or hi-res ?
2236 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2238 if(strstr(ptr, NOX("(1024x768)"))){
2242 gr_init(GR_1024, GR_DIRECT3D, depth);
2246 gr_init(GR_640, GR_DIRECT3D, depth);
2252 if ( Use_fullscreen_at_startup && !Is_standalone) {
2253 gr_init(GR_640, GR_DIRECTDRAW);
2256 gr_init(GR_640, GR_OPENGL);
2258 gr_init(GR_640, GR_SOFTWARE);
2262 if ( !Is_standalone ) {
2263 gr_init(GR_640, GR_DIRECTDRAW);
2266 gr_init(GR_640, GR_OPENGL);
2268 gr_init(GR_640, GR_SOFTWAREL);
2275 extern int Gr_inited;
2276 if(trying_d3d && !Gr_inited){
2277 extern char Device_init_error[512];
2279 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2288 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2289 Freespace_gamma = (float)atof(ptr);
2290 if ( Freespace_gamma < 0.1f ) {
2291 Freespace_gamma = 0.1f;
2292 } else if ( Freespace_gamma > 5.0f ) {
2293 Freespace_gamma = 5.0f;
2295 char tmp_gamma_string[32];
2296 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2297 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2299 gr_set_gamma(Freespace_gamma);
2301 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2304 display_title_screen();
2308 // attempt to load up master tracker registry info (login and password)
2309 Multi_tracker_id = -1;
2311 // pxo login and password
2312 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2314 nprintf(("Network","Error reading in PXO login data\n"));
2315 strcpy(Multi_tracker_login,"");
2317 strcpy(Multi_tracker_login,ptr);
2319 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2321 nprintf(("Network","Error reading PXO password\n"));
2322 strcpy(Multi_tracker_passwd,"");
2324 strcpy(Multi_tracker_passwd,ptr);
2327 // pxo squad name and password
2328 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2330 nprintf(("Network","Error reading in PXO squad name\n"));
2331 strcpy(Multi_tracker_squad_name, "");
2333 strcpy(Multi_tracker_squad_name, ptr);
2336 // If less than 48MB of RAM, use low memory model.
2337 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2338 mprintf(( "Using normal memory settings...\n" ));
2339 bm_set_low_mem(1); // Use every other frame of bitmaps
2341 mprintf(( "Using high memory settings...\n" ));
2342 bm_set_low_mem(0); // Use all frames of bitmaps
2345 // load non-darkening pixel defs
2346 palman_load_pixels();
2348 // hud shield icon stuff
2349 hud_shield_game_init();
2351 control_config_common_init(); // sets up localization stuff in the control config
2357 gamesnd_parse_soundstbl();
2362 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2367 player_controls_init();
2370 //if(!Is_standalone){
2378 ship_init(); // read in ships.tbl
2380 mission_campaign_init(); // load in the default campaign
2382 // navmap_init(); // init the navigation map system
2383 context_help_init();
2384 techroom_intel_init(); // parse species.tbl, load intel info
2386 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2387 init_animating_pointer();
2389 mission_brief_common_init(); // Mark all the briefing structures as empty.
2390 gr_font_init(); // loads up all fonts
2392 neb2_init(); // fullneb stuff
2396 player_tips_init(); // helpful tips
2399 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2400 pilot_load_pic_list();
2401 pilot_load_squad_pic_list();
2403 load_animating_pointer(NOX("cursor"), 0, 0);
2405 // initialize alpha colors
2406 alpha_colors_init();
2409 // Game_music_paused = 0;
2416 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2417 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2419 mprintf(("cfile_init() took %d\n", e1 - s1));
2420 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2423 char transfer_text[128];
2425 float Start_time = 0.0f;
2427 float Framerate = 0.0f;
2429 float Timing_total = 0.0f;
2430 float Timing_render2 = 0.0f;
2431 float Timing_render3 = 0.0f;
2432 float Timing_flip = 0.0f;
2433 float Timing_clear = 0.0f;
2435 MONITOR(NumPolysDrawn);
2441 void game_get_framerate()
2443 char text[128] = "";
2445 if ( frame_int == -1 ) {
2447 for (i=0; i<FRAME_FILTER; i++ ) {
2448 frametimes[i] = 0.0f;
2453 frametotal -= frametimes[frame_int];
2454 frametotal += flFrametime;
2455 frametimes[frame_int] = flFrametime;
2456 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2458 if ( frametotal != 0.0 ) {
2459 if ( Framecount >= FRAME_FILTER )
2460 Framerate = FRAME_FILTER / frametotal;
2462 Framerate = Framecount / frametotal;
2463 sprintf( text, NOX("FPS: %.1f"), Framerate );
2465 sprintf( text, NOX("FPS: ?") );
2469 if (Show_framerate) {
2470 gr_set_color_fast(&HUD_color_debug);
2471 gr_string( 570, 2, text );
2475 void game_show_framerate()
2479 cur_time = f2fl(timer_get_approx_seconds());
2480 if (cur_time - Start_time > 30.0f) {
2481 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2482 Start_time += 1000.0f;
2485 //mprintf(( "%s\n", text ));
2488 if ( Debug_dump_frames )
2492 // possibly show control checking info
2493 control_check_indicate();
2495 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2496 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2497 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2498 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2501 if ( Show_cpu == 1 ) {
2506 dy = gr_get_font_height() + 1;
2508 gr_set_color_fast(&HUD_color_debug);
2512 extern int D3D_textures_in;
2513 extern int D3D_textures_in_frame;
2514 extern int Glide_textures_in;
2515 extern int Glide_textures_in_frame;
2516 extern int Glide_explosion_vram;
2517 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2519 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2521 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2527 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2529 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2531 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2533 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2535 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2540 extern int Num_pairs; // Number of object pairs that were checked.
2541 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2544 extern int Num_pairs_checked; // What percent of object pairs were checked.
2545 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2547 Num_pairs_checked = 0;
2551 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2554 if ( Timing_total > 0.01f ) {
2555 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2557 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2559 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2561 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2563 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2573 dy = gr_get_font_height() + 1;
2575 gr_set_color_fast(&HUD_color_debug);
2578 extern int TotalRam;
2579 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2584 extern int Model_ram;
2585 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2589 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2591 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2593 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2597 extern int D3D_textures_in;
2598 extern int Glide_textures_in;
2599 extern int Glide_textures_in_frame;
2600 extern int Glide_explosion_vram;
2601 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2603 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2605 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2614 if ( Show_player_pos ) {
2618 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));
2621 MONITOR_INC(NumPolys, modelstats_num_polys);
2622 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2623 MONITOR_INC(NumVerts, modelstats_num_verts );
2625 modelstats_num_polys = 0;
2626 modelstats_num_polys_drawn = 0;
2627 modelstats_num_verts = 0;
2628 modelstats_num_sortnorms = 0;
2632 void game_show_standalone_framerate()
2634 float frame_rate=30.0f;
2635 if ( frame_int == -1 ) {
2637 for (i=0; i<FRAME_FILTER; i++ ) {
2638 frametimes[i] = 0.0f;
2643 frametotal -= frametimes[frame_int];
2644 frametotal += flFrametime;
2645 frametimes[frame_int] = flFrametime;
2646 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2648 if ( frametotal != 0.0 ) {
2649 if ( Framecount >= FRAME_FILTER ){
2650 frame_rate = FRAME_FILTER / frametotal;
2652 frame_rate = Framecount / frametotal;
2655 std_set_standalone_fps(frame_rate);
2659 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2660 void game_show_time_left()
2664 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2665 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2666 // checking how much time is left
2668 if ( Mission_end_time == -1 ){
2672 diff = f2i(Mission_end_time - Missiontime);
2673 // be sure to bash to 0. diff could be negative on frame that we quit mission
2678 hud_set_default_color();
2679 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2682 //========================================================================================
2683 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2684 //========================================================================================
2688 DCF(ai_pause,"Pauses ai")
2691 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2692 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2693 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2694 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2697 obj_init_all_ships_physics();
2700 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2701 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2704 DCF(single_step,"Single steps the game")
2707 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2708 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2709 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2710 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2712 last_single_step = 0; // Make so single step waits a frame before stepping
2715 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2716 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2719 DCF_BOOL(physics_pause, physics_paused)
2720 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2721 DCF_BOOL(ai_firing, Ai_firing_enabled )
2723 // Create some simple aliases to these commands...
2724 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2725 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2726 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2727 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2728 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2731 //========================================================================================
2732 //========================================================================================
2735 void game_training_pause_do()
2739 key = game_check_key();
2741 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2748 void game_increase_skill_level()
2751 if (Game_skill_level >= NUM_SKILL_LEVELS){
2752 Game_skill_level = 0;
2756 int Player_died_time;
2758 int View_percent = 100;
2761 DCF(view, "Sets the percent of the 3d view to render.")
2764 dc_get_arg(ARG_INT);
2765 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2766 View_percent = Dc_arg_int;
2768 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2774 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2778 dc_printf("View is set to %d%%\n", View_percent );
2783 // Set the clip region for the 3d rendering window
2784 void game_set_view_clip()
2786 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2787 // Set the clip region for the letterbox "dead view"
2788 int yborder = gr_screen.max_h/4;
2790 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2791 // J.S. I've changed my ways!! See the new "no constants" code!!!
2792 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2794 // Set the clip region for normal view
2795 if ( View_percent >= 100 ) {
2798 int xborder, yborder;
2800 if ( View_percent < 5 ) {
2804 float fp = i2fl(View_percent)/100.0f;
2805 int fi = fl2i(fl_sqrt(fp)*100.0f);
2806 if ( fi > 100 ) fi=100;
2808 xborder = ( gr_screen.max_w*(100-fi) )/200;
2809 yborder = ( gr_screen.max_h*(100-fi) )/200;
2811 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2817 void show_debug_stuff()
2820 int laser_count = 0, missile_count = 0;
2822 for (i=0; i<MAX_OBJECTS; i++) {
2823 if (Objects[i].type == OBJ_WEAPON){
2824 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2826 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2832 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2835 extern int Tool_enabled;
2840 int tst_bitmap = -1;
2842 float tst_offset, tst_offset_total;
2845 void game_tst_frame_pre()
2853 g3_rotate_vertex(&v, &tst_pos);
2854 g3_project_vertex(&v);
2857 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2861 // big ship? always tst
2863 // within 3000 meters
2864 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2868 // within 300 meters
2869 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2876 void game_tst_frame()
2886 tst_time = time(NULL);
2888 // load the tst bitmap
2889 switch((int)frand_range(0.0f, 3.0)){
2891 tst_bitmap = bm_load("ig_jim");
2893 mprintf(("TST 0\n"));
2897 tst_bitmap = bm_load("ig_kan");
2899 mprintf(("TST 1\n"));
2903 tst_bitmap = bm_load("ig_jim");
2905 mprintf(("TST 2\n"));
2909 tst_bitmap = bm_load("ig_kan");
2911 mprintf(("TST 3\n"));
2920 // get the tst bitmap dimensions
2922 bm_get_info(tst_bitmap, &w, &h);
2925 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2927 snd_play(&Snds[SND_VASUDAN_BUP]);
2929 // tst x and direction
2933 tst_offset_total = (float)w;
2934 tst_offset = (float)w;
2936 tst_x = (float)gr_screen.max_w;
2937 tst_offset_total = (float)-w;
2938 tst_offset = (float)w;
2946 float diff = (tst_offset_total / 0.5f) * flFrametime;
2952 tst_offset -= fl_abs(diff);
2953 } else if(tst_mode == 2){
2956 tst_offset -= fl_abs(diff);
2960 gr_set_bitmap(tst_bitmap);
2961 gr_bitmap((int)tst_x, (int)tst_y);
2964 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2968 // if we passed the switch point
2969 if(tst_offset <= 0.0f){
2974 tst_stamp = timestamp(1000);
2975 tst_offset = fl_abs(tst_offset_total);
2986 void game_tst_mark(object *objp, ship *shipp)
2995 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2998 sip = &Ship_info[shipp->ship_info_index];
3005 tst_pos = objp->pos;
3006 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3012 extern void render_shields();
3014 void player_repair_frame(float frametime)
3016 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3018 for(idx=0;idx<MAX_PLAYERS;idx++){
3021 np = &Net_players[idx];
3023 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)){
3025 // don't rearm/repair if the player is dead or dying/departing
3026 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3027 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3032 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3033 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3039 #define NUM_FRAMES_TEST 300
3040 #define NUM_MIXED_SOUNDS 16
3041 void do_timing_test(float flFrametime)
3043 static int framecount = 0;
3044 static int test_running = 0;
3045 static float test_time = 0.0f;
3047 static int snds[NUM_MIXED_SOUNDS];
3050 if ( test_running ) {
3052 test_time += flFrametime;
3053 if ( framecount >= NUM_FRAMES_TEST ) {
3055 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3056 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3061 if ( Test_begin == 1 ) {
3067 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3070 // start looping digital sounds
3071 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3072 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3079 DCF(dcf_fov, "Change the field of view")
3082 dc_get_arg(ARG_FLOAT|ARG_NONE);
3083 if ( Dc_arg_type & ARG_NONE ) {
3084 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3085 dc_printf( "Zoom factor reset\n" );
3087 if ( Dc_arg_type & ARG_FLOAT ) {
3088 if (Dc_arg_float < 0.25f) {
3089 Viewer_zoom = 0.25f;
3090 dc_printf("Zoom factor pinned at 0.25.\n");
3091 } else if (Dc_arg_float > 1.25f) {
3092 Viewer_zoom = 1.25f;
3093 dc_printf("Zoom factor pinned at 1.25.\n");
3095 Viewer_zoom = Dc_arg_float;
3101 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3104 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3108 DCF(framerate_cap, "Sets the framerate cap")
3111 dc_get_arg(ARG_INT);
3112 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3113 Framerate_cap = Dc_arg_int;
3115 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3121 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3122 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3123 dc_printf("[n] must be from 1 to 120.\n");
3127 if ( Framerate_cap )
3128 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3130 dc_printf("There is no framerate cap currently active.\n");
3134 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3135 int Show_viewing_from_self = 0;
3137 void say_view_target()
3139 object *view_target;
3141 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3142 view_target = &Objects[Player_ai->target_objnum];
3144 view_target = Player_obj;
3146 if (Game_mode & GM_DEAD) {
3147 if (Player_ai->target_objnum != -1)
3148 view_target = &Objects[Player_ai->target_objnum];
3151 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3152 if (view_target != Player_obj){
3154 char *view_target_name = NULL;
3155 switch(Objects[Player_ai->target_objnum].type) {
3157 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3160 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3161 Viewer_mode &= ~VM_OTHER_SHIP;
3163 case OBJ_JUMP_NODE: {
3164 char jump_node_name[128];
3165 strcpy(jump_node_name, XSTR( "jump node", 184));
3166 view_target_name = jump_node_name;
3167 Viewer_mode &= ~VM_OTHER_SHIP;
3176 if ( view_target_name ) {
3177 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3178 Show_viewing_from_self = 1;
3181 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3182 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3183 Show_viewing_from_self = 1;
3185 if (Show_viewing_from_self)
3186 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3191 Last_view_target = view_target;
3195 float Game_hit_x = 0.0f;
3196 float Game_hit_y = 0.0f;
3198 // Reset at the beginning of each frame
3199 void game_whack_reset()
3205 // Apply a 2d whack to the player
3206 void game_whack_apply( float x, float y )
3208 // Do some force feedback
3209 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3215 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3218 // call to apply a "shudder"
3219 void game_shudder_apply(int time, float intensity)
3221 Game_shudder_time = timestamp(time);
3222 Game_shudder_total = time;
3223 Game_shudder_intensity = intensity;
3226 #define FF_SCALE 10000
3227 void apply_hud_shake(matrix *eye_orient)
3229 if (Viewer_obj == Player_obj) {
3230 physics_info *pi = &Player_obj->phys_info;
3238 // Make eye shake due to afterburner
3239 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3242 dtime = timestamp_until(pi->afterburner_decay);
3246 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3247 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3250 // Make eye shake due to engine wash
3252 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3255 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3256 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3258 // get the intensity
3259 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3263 vm_vec_rand_vec_quick(&rand_vec);
3266 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3270 // make hud shake due to shuddering
3271 if(Game_shudder_time != -1){
3272 // if the timestamp has elapsed
3273 if(timestamp_elapsed(Game_shudder_time)){
3274 Game_shudder_time = -1;
3276 // otherwise apply some shudder
3280 dtime = timestamp_until(Game_shudder_time);
3284 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));
3285 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));
3290 vm_angles_2_matrix(&tm, &tangles);
3291 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3292 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3293 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3294 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3299 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3301 // Player's velocity just before he blew up. Used to keep camera target moving.
3302 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3304 // Set eye_pos and eye_orient based on view mode.
3305 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3309 static int last_Viewer_mode = 0;
3310 static int last_Game_mode = 0;
3311 static int last_Viewer_objnum = -1;
3313 // This code is supposed to detect camera "cuts"... like going between
3316 // determine if we need to regenerate the nebula
3317 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3318 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3319 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3320 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3321 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3322 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3323 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3324 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3325 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3328 // regenerate the nebula
3332 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3333 //mprintf(( "************** Camera cut! ************\n" ));
3334 last_Viewer_mode = Viewer_mode;
3335 last_Game_mode = Game_mode;
3337 // Camera moved. Tell stars & debris to not do blurring.
3343 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3344 player_display_packlock_view();
3347 game_set_view_clip();
3349 if (Game_mode & GM_DEAD) {
3350 vector vec_to_deader, view_pos;
3353 Viewer_mode |= VM_DEAD_VIEW;
3355 if (Player_ai->target_objnum != -1) {
3356 int view_from_player = 1;
3358 if (Viewer_mode & VM_OTHER_SHIP) {
3359 // View from target.
3360 Viewer_obj = &Objects[Player_ai->target_objnum];
3362 last_Viewer_objnum = Player_ai->target_objnum;
3364 if ( Viewer_obj->type == OBJ_SHIP ) {
3365 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3366 view_from_player = 0;
3369 last_Viewer_objnum = -1;
3372 if ( view_from_player ) {
3373 // View target from player ship.
3375 *eye_pos = Player_obj->pos;
3376 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3377 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3380 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3382 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3383 dist += flFrametime * 16.0f;
3385 vm_vec_scale(&vec_to_deader, -dist);
3386 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3388 view_pos = Player_obj->pos;
3390 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3391 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3392 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3393 Dead_player_last_vel = Player_obj->phys_info.vel;
3394 //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));
3395 } else if (Player_ai->target_objnum != -1) {
3396 view_pos = Objects[Player_ai->target_objnum].pos;
3398 // Make camera follow explosion, but gradually slow down.
3399 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3400 view_pos = Player_obj->pos;
3401 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3402 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3405 *eye_pos = Dead_camera_pos;
3407 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3409 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3414 // if supernova shockwave
3415 if(supernova_camera_cut()){
3419 // call it dead view
3420 Viewer_mode |= VM_DEAD_VIEW;
3422 // set eye pos and orient
3423 supernova_set_view(eye_pos, eye_orient);
3425 // If already blown up, these other modes can override.
3426 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3427 Viewer_mode &= ~VM_DEAD_VIEW;
3429 Viewer_obj = Player_obj;
3431 if (Viewer_mode & VM_OTHER_SHIP) {
3432 if (Player_ai->target_objnum != -1){
3433 Viewer_obj = &Objects[Player_ai->target_objnum];
3434 last_Viewer_objnum = Player_ai->target_objnum;
3436 Viewer_mode &= ~VM_OTHER_SHIP;
3437 last_Viewer_objnum = -1;
3440 last_Viewer_objnum = -1;
3443 if (Viewer_mode & VM_EXTERNAL) {
3446 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3447 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3449 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3451 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3452 vm_vec_normalize(&eye_dir);
3453 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3456 // Modify the orientation based on head orientation.
3457 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3459 } else if ( Viewer_mode & VM_CHASE ) {
3462 if ( Viewer_obj->phys_info.speed < 0.1 )
3463 move_dir = Viewer_obj->orient.fvec;
3465 move_dir = Viewer_obj->phys_info.vel;
3466 vm_vec_normalize(&move_dir);
3469 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3470 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3471 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3472 vm_vec_normalize(&eye_dir);
3474 // JAS: I added the following code because if you slew up using
3475 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3476 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3477 // call because the up and the forward vector are the same. I fixed
3478 // it by adding in a fraction of the right vector all the time to the
3480 vector tmp_up = Viewer_obj->orient.uvec;
3481 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3483 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3486 // Modify the orientation based on head orientation.
3487 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3488 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3489 *eye_pos = Camera_pos;
3491 ship * shipp = &Ships[Player_obj->instance];
3493 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3494 vm_vec_normalize(&eye_dir);
3495 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3498 // get an eye position based upon the correct type of object
3499 switch(Viewer_obj->type){
3501 // make a call to get the eye point for the player object
3502 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3505 // make a call to get the eye point for the player object
3506 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3512 #ifdef JOHNS_DEBUG_CODE
3513 john_debug_stuff(&eye_pos, &eye_orient);
3519 apply_hud_shake(eye_orient);
3521 // setup neb2 rendering
3522 neb2_render_setup(eye_pos, eye_orient);
3526 extern void ai_debug_render_stuff();
3529 int Game_subspace_effect = 0;
3530 DCF_BOOL( subspace, Game_subspace_effect );
3532 // Does everything needed to render a frame
3533 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3537 g3_start_frame(game_zbuffer);
3538 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3540 // maybe offset the HUD (jitter stuff)
3541 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3542 HUD_set_offsets(Viewer_obj, !dont_offset);
3544 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3545 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3546 // must be done before ships are rendered
3547 if ( MULTIPLAYER_CLIENT ) {
3548 shield_point_multi_setup();
3551 if ( Game_subspace_effect ) {
3552 stars_draw(0,0,0,1);
3554 stars_draw(1,1,1,0);
3557 obj_render_all(obj_render);
3558 beam_render_all(); // render all beam weapons
3559 particle_render_all(); // render particles after everything else.
3560 trail_render_all(); // render missilie trails after everything else.
3561 mflash_render_all(); // render all muzzle flashes
3563 // Why do we not show the shield effect in these modes? Seems ok.
3564 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3568 // render nebula lightning
3571 // render local player nebula
3572 neb2_render_player();
3575 ai_debug_render_stuff();
3578 #ifndef RELEASE_REAL
3579 // game_framerate_check();
3583 extern void snd_spew_debug_info();
3584 snd_spew_debug_info();
3587 //================ END OF 3D RENDERING STUFF ====================
3591 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3592 hud_maybe_clear_head_area();
3593 anim_render_all(0, flFrametime);
3596 extern int Multi_display_netinfo;
3597 if(Multi_display_netinfo){
3598 extern void multi_display_netinfo();
3599 multi_display_netinfo();
3602 game_tst_frame_pre();
3605 do_timing_test(flFrametime);
3609 extern int OO_update_index;
3610 multi_rate_display(OO_update_index, 375, 0);
3615 extern void oo_display();
3622 //#define JOHNS_DEBUG_CODE 1
3624 #ifdef JOHNS_DEBUG_CODE
3625 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3627 //if ( keyd_pressed[KEY_LSHIFT] )
3629 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3631 model_subsystem *turret = tsys->system_info;
3633 if (turret->type == SUBSYSTEM_TURRET ) {
3635 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3637 ship_model_start(tobj);
3639 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3640 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3641 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3643 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3645 ship_model_stop(tobj);
3655 // following function for dumping frames for purposes of building trailers.
3658 // function to toggle state of dumping every frame into PCX when playing the game
3659 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3663 if ( Debug_dump_frames == 0 ) {
3665 Debug_dump_frames = 15;
3666 Debug_dump_trigger = 0;
3667 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3668 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3671 Debug_dump_frames = 0;
3672 Debug_dump_trigger = 0;
3673 gr_dump_frame_stop();
3674 dc_printf( "Frame dumping is now OFF\n" );
3680 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3684 if ( Debug_dump_frames == 0 ) {
3686 Debug_dump_frames = 15;
3687 Debug_dump_trigger = 1;
3688 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3689 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3692 Debug_dump_frames = 0;
3693 Debug_dump_trigger = 0;
3694 gr_dump_frame_stop();
3695 dc_printf( "Frame dumping is now OFF\n" );
3701 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3705 if ( Debug_dump_frames == 0 ) {
3707 Debug_dump_frames = 30;
3708 Debug_dump_trigger = 0;
3709 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3710 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3713 Debug_dump_frames = 0;
3714 Debug_dump_trigger = 0;
3715 gr_dump_frame_stop();
3716 dc_printf( "Frame dumping is now OFF\n" );
3722 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3726 if ( Debug_dump_frames == 0 ) {
3728 Debug_dump_frames = 30;
3729 Debug_dump_trigger = 1;
3730 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3731 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3734 Debug_dump_frames = 0;
3735 Debug_dump_trigger = 0;
3736 gr_dump_frame_stop();
3737 dc_printf( "Triggered frame dumping is now OFF\n" );
3743 void game_maybe_dump_frame()
3745 if ( !Debug_dump_frames ){
3749 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3756 Debug_dump_frame_num++;
3762 extern int Player_dead_state;
3764 // Flip the page and time how long it took.
3765 void game_flip_page_and_time_it()
3769 t1 = timer_get_fixed_seconds();
3771 t2 = timer_get_fixed_seconds();
3773 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3774 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3777 void game_simulation_frame()
3779 // blow ships up in multiplayer dogfight
3780 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){
3781 // blow up all non-player ships
3782 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3785 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3787 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)){
3788 moveup = GET_NEXT(moveup);
3791 shipp = &Ships[Objects[moveup->objnum].instance];
3792 sip = &Ship_info[shipp->ship_info_index];
3794 // only blow up small ships
3795 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3796 // function to simply explode a ship where it is currently at
3797 ship_self_destruct( &Objects[moveup->objnum] );
3800 moveup = GET_NEXT(moveup);
3806 // process AWACS stuff - do this first thing
3809 // single player, set Player hits_this_frame to 0
3810 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3811 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3812 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3816 supernova_process();
3817 if(supernova_active() >= 5){
3821 // fire targeting lasers now so that
3822 // 1 - created this frame
3823 // 2 - collide this frame
3824 // 3 - render this frame
3825 // 4 - ignored and deleted next frame
3826 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3828 ship_process_targeting_lasers();
3830 // do this here so that it works for multiplayer
3832 // get viewer direction
3833 int viewer_direction = PHYSICS_VIEWER_REAR;
3835 if(Viewer_mode == 0){
3836 viewer_direction = PHYSICS_VIEWER_FRONT;
3838 if(Viewer_mode & VM_PADLOCK_UP){
3839 viewer_direction = PHYSICS_VIEWER_UP;
3841 else if(Viewer_mode & VM_PADLOCK_REAR){
3842 viewer_direction = PHYSICS_VIEWER_REAR;
3844 else if(Viewer_mode & VM_PADLOCK_LEFT){
3845 viewer_direction = PHYSICS_VIEWER_LEFT;
3847 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3848 viewer_direction = PHYSICS_VIEWER_RIGHT;
3851 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3853 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3856 #define VM_PADLOCK_UP (1 << 7)
3857 #define VM_PADLOCK_REAR (1 << 8)
3858 #define VM_PADLOCK_LEFT (1 << 9)
3859 #define VM_PADLOCK_RIGHT (1 << 10)
3861 // evaluate mission departures and arrivals before we process all objects.
3862 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3864 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3865 // ships/wing packets.
3866 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3867 mission_parse_eval_stuff();
3870 // if we're an observer, move ourselves seperately from the standard physics
3871 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3872 obj_observer_move(flFrametime);
3875 // move all the objects now
3876 obj_move_all(flFrametime);
3878 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3879 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3880 // ship_check_cargo_all();
3881 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3882 mission_eval_goals();
3886 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3887 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3888 training_check_objectives();
3891 // do all interpolation now
3892 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3893 // client side processing of warping in effect stages
3894 multi_do_client_warp(flFrametime);
3896 // client side movement of an observer
3897 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3898 obj_observer_move(flFrametime);
3901 // move all objects - does interpolation now as well
3902 obj_move_all(flFrametime);
3905 // only process the message queue when the player is "in" the game
3906 if ( !Pre_player_entry ){
3907 message_queue_process(); // process any messages send to the player
3910 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3911 message_maybe_distort(); // maybe distort incoming message if comms damaged
3912 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3913 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3914 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3917 if(!(Game_mode & GM_STANDALONE_SERVER)){
3918 // process some stuff every frame (before frame is rendered)
3919 emp_process_local();
3921 hud_update_frame(); // update hud systems
3923 if (!physics_paused) {
3924 // Move particle system
3925 particle_move_all(flFrametime);
3927 // Move missile trails
3928 trail_move_all(flFrametime);
3930 // process muzzle flashes
3931 mflash_process_all();
3933 // Flash the gun flashes
3934 shipfx_flash_do_frame(flFrametime);
3936 shockwave_move_all(flFrametime); // update all the shockwaves
3939 // subspace missile strikes
3942 obj_snd_do_frame(); // update the object-linked persistant sounds
3943 game_maybe_update_sound_environment();
3944 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3946 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3948 if ( Game_subspace_effect ) {
3949 game_start_subspace_ambient_sound();
3955 // Maybe render and process the dead-popup
3956 void game_maybe_do_dead_popup(float frametime)
3958 if ( popupdead_is_active() ) {
3960 int choice = popupdead_do_frame(frametime);
3962 if ( Game_mode & GM_NORMAL ) {
3966 if(game_do_cd_mission_check(Game_current_mission_filename)){
3967 gameseq_post_event(GS_EVENT_ENTER_GAME);
3969 gameseq_post_event(GS_EVENT_MAIN_MENU);
3974 gameseq_post_event(GS_EVENT_END_GAME);
3979 if(game_do_cd_mission_check(Game_current_mission_filename)){
3980 gameseq_post_event(GS_EVENT_START_GAME);
3982 gameseq_post_event(GS_EVENT_MAIN_MENU);
3986 // this should only happen during a red alert mission
3989 Assert(The_mission.red_alert);
3990 if(!The_mission.red_alert){
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);
4000 // choose the previous mission
4001 mission_campaign_previous_mission();
4003 if(game_do_cd_mission_check(Game_current_mission_filename)){
4004 gameseq_post_event(GS_EVENT_START_GAME);
4006 gameseq_post_event(GS_EVENT_MAIN_MENU);
4017 case POPUPDEAD_DO_MAIN_HALL:
4018 multi_quit_game(PROMPT_NONE,-1);
4021 case POPUPDEAD_DO_RESPAWN:
4022 multi_respawn_normal();
4023 event_music_player_respawn();
4026 case POPUPDEAD_DO_OBSERVER:
4027 multi_respawn_observer();
4028 event_music_player_respawn_as_observer();
4037 if ( leave_popup ) {
4043 // returns true if player is actually in a game_play stats
4044 int game_actually_playing()
4048 state = gameseq_get_state();
4049 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4055 // Draw the 2D HUD gauges
4056 void game_render_hud_2d()
4058 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4062 HUD_render_2d(flFrametime);
4066 // Draw the 3D-dependant HUD gauges
4067 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4069 g3_start_frame(0); // 0 = turn zbuffering off
4070 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4072 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4073 HUD_render_3d(flFrametime);
4077 game_sunspot_process(flFrametime);
4079 // Diminish the palette effect
4080 game_flash_diminish(flFrametime);
4088 int actually_playing;
4089 fix total_time1, total_time2;
4090 fix render2_time1=0, render2_time2=0;
4091 fix render3_time1=0, render3_time2=0;
4092 fix flip_time1=0, flip_time2=0;
4093 fix clear_time1=0, clear_time2=0;
4099 if (Framerate_delay) {
4100 int start_time = timer_get_milliseconds();
4101 while (timer_get_milliseconds() < start_time + Framerate_delay)
4107 demo_do_frame_start();
4109 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4114 // start timing frame
4115 timing_frame_start();
4117 total_time1 = timer_get_fixed_seconds();
4119 // var to hold which state we are in
4120 actually_playing = game_actually_playing();
4122 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4123 if (!(Game_mode & GM_STANDALONE_SERVER)){
4124 Assert( OBJ_INDEX(Player_obj) >= 0 );
4128 if (Missiontime > Entry_delay_time){
4129 Pre_player_entry = 0;
4131 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4134 // Note: These are done even before the player enters, else buffers can overflow.
4135 if (! (Game_mode & GM_STANDALONE_SERVER)){
4139 shield_frame_init();
4141 if ( Player->control_mode != PCM_NORMAL )
4144 if ( !Pre_player_entry && actually_playing ) {
4145 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4147 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4148 game_process_keys();
4150 // don't read flying controls if we're playing a demo back
4151 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4152 read_player_controls( Player_obj, flFrametime);
4156 // if we're not the master, we may have to send the server-critical ship status button_info bits
4157 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4158 multi_maybe_send_ship_status();
4163 // Reset the whack stuff
4166 // These two lines must be outside of Pre_player_entry code,
4167 // otherwise too many lights are added.
4170 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4174 game_simulation_frame();
4176 // if not actually in a game play state, then return. This condition could only be true in
4177 // a multiplayer game.
4178 if ( !actually_playing ) {
4179 Assert( Game_mode & GM_MULTIPLAYER );
4183 if (!Pre_player_entry) {
4184 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4185 clear_time1 = timer_get_fixed_seconds();
4186 // clear the screen to black
4188 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4192 clear_time2 = timer_get_fixed_seconds();
4193 render3_time1 = timer_get_fixed_seconds();
4194 game_render_frame_setup(&eye_pos, &eye_orient);
4195 game_render_frame( &eye_pos, &eye_orient );
4197 // save the eye position and orientation
4198 if ( Game_mode & GM_MULTIPLAYER ) {
4199 Net_player->s_info.eye_pos = eye_pos;
4200 Net_player->s_info.eye_orient = eye_orient;
4203 hud_show_target_model();
4205 // check to see if we should display the death died popup
4206 if(Game_mode & GM_DEAD_BLEW_UP){
4207 if(Game_mode & GM_MULTIPLAYER){
4208 // catch the situation where we're supposed to be warping out on this transition
4209 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4210 gameseq_post_event(GS_EVENT_DEBRIEF);
4211 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4212 Player_died_popup_wait = -1;
4216 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4217 Player_died_popup_wait = -1;
4223 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4224 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4225 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4226 if(!popupdead_is_active()){
4230 Player_multi_died_check = -1;
4234 render3_time2 = timer_get_fixed_seconds();
4235 render2_time1 = timer_get_fixed_seconds();
4238 game_get_framerate();
4239 game_show_framerate();
4241 game_show_time_left();
4243 // Draw the 2D HUD gauges
4244 if(supernova_active() < 3){
4245 game_render_hud_2d();
4248 game_set_view_clip();
4250 // Draw 3D HUD gauges
4251 game_render_hud_3d(&eye_pos, &eye_orient);
4255 render2_time2 = timer_get_fixed_seconds();
4257 // maybe render and process the dead popup
4258 game_maybe_do_dead_popup(flFrametime);
4260 // start timing frame
4261 timing_frame_stop();
4262 // timing_display(30, 10);
4264 // If a regular popup is active, don't flip (popup code flips)
4265 if( !popup_running_state() ){
4266 flip_time1 = timer_get_fixed_seconds();
4267 game_flip_page_and_time_it();
4268 flip_time2 = timer_get_fixed_seconds();
4272 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4275 game_show_standalone_framerate();
4279 game_do_training_checks();
4282 // process lightning (nebula only)
4285 total_time2 = timer_get_fixed_seconds();
4287 // Got some timing numbers
4288 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4289 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4290 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4291 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4292 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4295 demo_do_frame_end();
4297 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4303 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4304 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4305 // died. This resulted in screwed up death sequences.
4307 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4308 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4309 static int timer_paused=0;
4310 static int stop_count,start_count;
4311 static int time_stopped,time_started;
4312 int saved_timestamp_ticker = -1;
4314 void game_reset_time()
4316 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4320 // Last_time = timer_get_fixed_seconds();
4326 void game_stop_time()
4328 if (timer_paused==0) {
4330 time = timer_get_fixed_seconds();
4331 // Save how much time progressed so far in the frame so we can
4332 // use it when we unpause.
4333 Last_delta_time = time - Last_time;
4335 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4336 if (Last_delta_time < 0) {
4337 #if defined(TIMER_TEST) && !defined(NDEBUG)
4338 Int3(); //get Matt!!!!
4340 Last_delta_time = 0;
4342 #if defined(TIMER_TEST) && !defined(NDEBUG)
4343 time_stopped = time;
4346 // Stop the timer_tick stuff...
4347 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4348 saved_timestamp_ticker = timestamp_ticker;
4352 #if defined(TIMER_TEST) && !defined(NDEBUG)
4357 void game_start_time()
4360 Assert(timer_paused >= 0);
4361 if (timer_paused==0) {
4363 time = timer_get_fixed_seconds();
4364 #if defined(TIMER_TEST) && !defined(NDEBUG)
4366 Int3(); //get Matt!!!!
4369 // Take current time, and set it backwards to account for time
4370 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4371 // will be correct when it goes to calculate the frametime next
4373 Last_time = time - Last_delta_time;
4374 #if defined(TIMER_TEST) && !defined(NDEBUG)
4375 time_started = time;
4378 // Restore the timer_tick stuff...
4379 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4380 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4381 timestamp_ticker = saved_timestamp_ticker;
4382 saved_timestamp_ticker = -1;
4385 #if defined(TIMER_TEST) && !defined(NDEBUG)
4391 void game_set_frametime(int state)
4394 float frame_cap_diff;
4396 thistime = timer_get_fixed_seconds();
4398 if ( Last_time == 0 )
4399 Frametime = F1_0 / 30;
4401 Frametime = thistime - Last_time;
4403 // Frametime = F1_0 / 30;
4405 fix debug_frametime = Frametime; // Just used to display frametime.
4407 // If player hasn't entered mission yet, make frame take 1/4 second.
4408 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4411 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4413 fix frame_speed = F1_0 / Debug_dump_frames;
4415 if (Frametime > frame_speed ){
4416 nprintf(("warning","slow frame: %x\n",Frametime));
4419 thistime = timer_get_fixed_seconds();
4420 Frametime = thistime - Last_time;
4421 } while (Frametime < frame_speed );
4423 Frametime = frame_speed;
4427 Assert( Framerate_cap > 0 );
4429 // Cap the framerate so it doesn't get too high.
4433 cap = F1_0/Framerate_cap;
4434 if (Frametime < cap) {
4435 thistime = cap - Frametime;
4436 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4437 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4439 thistime = timer_get_fixed_seconds();
4443 if((Game_mode & GM_STANDALONE_SERVER) &&
4444 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4446 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4447 Sleep((DWORD)(frame_cap_diff*1000));
4449 thistime += fl2f((frame_cap_diff));
4451 Frametime = thistime - Last_time;
4454 // If framerate is too low, cap it.
4455 if (Frametime > MAX_FRAMETIME) {
4457 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4459 // to remove warnings in release build
4460 debug_frametime = fl2f(flFrametime);
4462 Frametime = MAX_FRAMETIME;
4465 Frametime = fixmul(Frametime, Game_time_compression);
4467 Last_time = thistime;
4468 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4470 flFrametime = f2fl(Frametime);
4471 //if(!(Game_mode & GM_PLAYING_DEMO)){
4472 timestamp_inc(flFrametime);
4474 /* if ((Framecount > 0) && (Framecount < 10)) {
4475 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4480 // This is called from game_do_frame(), and from navmap_do_frame()
4481 void game_update_missiontime()
4483 // TODO JAS: Put in if and move this into game_set_frametime,
4484 // fix navmap to call game_stop/start_time
4485 //if ( !timer_paused )
4486 Missiontime += Frametime;
4489 void game_do_frame()
4491 game_set_frametime(GS_STATE_GAME_PLAY);
4492 game_update_missiontime();
4494 if (Game_mode & GM_STANDALONE_SERVER) {
4495 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4498 if ( game_single_step && (last_single_step == game_single_step) ) {
4499 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4500 while( key_checkch() == 0 )
4502 os_set_title( XSTR( "FreeSpace", 171) );
4503 Last_time = timer_get_fixed_seconds();
4506 last_single_step = game_single_step;
4508 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4509 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4513 Keep_mouse_centered = 0;
4514 monitor_update(); // Update monitor variables
4517 void multi_maybe_do_frame()
4519 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4524 int Joymouse_button_status = 0;
4526 // Flush all input devices
4534 Joymouse_button_status = 0;
4536 //mprintf(("Game flush!\n" ));
4539 // function for multiplayer only which calls game_do_state_common() when running the
4541 void game_do_dc_networking()
4543 Assert( Game_mode & GM_MULTIPLAYER );
4545 game_do_state_common( gameseq_get_state() );
4548 // Call this whenever in a loop, or when you need to check for a keystroke.
4549 int game_check_key()
4555 // convert keypad enter to normal enter
4556 if ((k & KEY_MASK) == KEY_PADENTER)
4557 k = (k & ~KEY_MASK) | KEY_ENTER;
4564 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4565 static int Demo_show_trailer_timestamp = 0;
4567 void demo_reset_trailer_timer()
4569 Demo_show_trailer_timestamp = timer_get_milliseconds();
4572 void demo_maybe_show_trailer(int k)
4575 // if key pressed, reset demo trailer timer
4577 demo_reset_trailer_timer();
4581 // if mouse moved, reset demo trailer timer
4584 mouse_get_delta(&dx, &dy);
4585 if ( (dx > 0) || (dy > 0) ) {
4586 demo_reset_trailer_timer();
4590 // if joystick has moved, reset demo trailer timer
4593 joy_get_delta(&dx, &dy);
4594 if ( (dx > 0) || (dy > 0) ) {
4595 demo_reset_trailer_timer();
4599 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4600 // the low-level code. Ugly, I know... but was the simplest and most
4603 // if 30 seconds since last demo trailer time reset, launch movie
4604 if ( os_foreground() ) {
4605 int now = timer_get_milliseconds();
4606 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4607 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4609 movie_play( NOX("fstrailer2.mve") );
4610 demo_reset_trailer_timer();
4618 // same as game_check_key(), except this is used while actually in the game. Since there
4619 // generally are differences between game control keys and general UI keys, makes sense to
4620 // have seperate functions for each case. If you are not checking a game control while in a
4621 // mission, you should probably be using game_check_key() instead.
4626 if (!os_foreground()) {
4631 // If we're in a single player game, pause it.
4632 if (!(Game_mode & GM_MULTIPLAYER)){
4633 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4634 game_process_pause_key();
4642 demo_maybe_show_trailer(k);
4645 // Move the mouse cursor with the joystick.
4646 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4647 // Move the mouse cursor with the joystick
4651 joy_get_pos( &jx, &jy, &jz, &jr );
4653 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4654 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4657 mouse_get_real_pos( &mx, &my );
4658 mouse_set_pos( mx+dx, my+dy );
4663 m = mouse_down(MOUSE_LEFT_BUTTON);
4665 if ( j != Joymouse_button_status ) {
4666 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4667 Joymouse_button_status = j;
4669 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4670 } else if ( (!j) && (m) ) {
4671 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4676 // if we should be ignoring keys because of some multiplayer situations
4677 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4681 // If a popup is running, don't process all the Fn keys
4682 if( popup_active() ) {
4686 state = gameseq_get_state();
4688 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4691 case KEY_DEBUGGED + KEY_BACKSP:
4696 launch_context_help();
4701 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4703 // don't allow f2 while warping out in multiplayer
4704 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4709 case GS_STATE_INITIAL_PLAYER_SELECT:
4710 case GS_STATE_OPTIONS_MENU:
4711 case GS_STATE_HUD_CONFIG:
4712 case GS_STATE_CONTROL_CONFIG:
4713 case GS_STATE_DEATH_DIED:
4714 case GS_STATE_DEATH_BLEW_UP:
4715 case GS_STATE_VIEW_MEDALS:
4719 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4726 // hotkey selection screen -- only valid from briefing and beyond.
4729 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) ) {
4730 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4736 case KEY_DEBUGGED + KEY_F3:
4737 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4740 case KEY_DEBUGGED + KEY_F4:
4741 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4745 if(Game_mode & GM_MULTIPLAYER){
4746 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4747 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4751 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4752 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4758 case KEY_ESC | KEY_SHIFTED:
4759 // make sure to quit properly out of multiplayer
4760 if(Game_mode & GM_MULTIPLAYER){
4761 multi_quit_game(PROMPT_NONE);
4764 gameseq_post_event( GS_EVENT_QUIT_GAME );
4769 case KEY_DEBUGGED + KEY_P:
4772 case KEY_PRINT_SCRN:
4774 static int counter = 0;
4779 sprintf( tmp_name, NOX("screen%02d"), counter );
4781 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4782 gr_print_screen(tmp_name);
4790 case KEY_SHIFTED | KEY_ENTER: {
4792 #if !defined(NDEBUG)
4794 if ( Game_mode & GM_NORMAL ){
4798 // if we're in multiplayer mode, do some special networking
4799 if(Game_mode & GM_MULTIPLAYER){
4800 debug_console(game_do_dc_networking);
4807 if ( Game_mode & GM_NORMAL )
4821 gameseq_post_event(GS_EVENT_QUIT_GAME);
4824 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4827 void camera_set_position( vector *pos )
4832 void camera_set_orient( matrix *orient )
4834 Camera_orient = *orient;
4837 void camera_set_velocity( vector *vel, int instantaneous )
4839 Camera_desired_velocity.x = 0.0f;
4840 Camera_desired_velocity.y = 0.0f;
4841 Camera_desired_velocity.z = 0.0f;
4843 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4844 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4845 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4847 if ( instantaneous ) {
4848 Camera_velocity = Camera_desired_velocity;
4856 vector new_vel, delta_pos;
4858 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4859 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4860 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4862 Camera_velocity = new_vel;
4864 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4866 vm_vec_add2( &Camera_pos, &delta_pos );
4868 float ot = Camera_time+0.0f;
4870 Camera_time += flFrametime;
4872 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4875 tmp.z = 4.739f; // always go this fast forward.
4877 // pick x and y velocities so they are always on a
4878 // circle with a 25 m radius.
4880 float tmp_angle = frand()*PI2;
4882 tmp.x = 22.0f * (float)sin(tmp_angle);
4883 tmp.y = -22.0f * (float)cos(tmp_angle);
4885 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4887 //mprintf(( "Changing velocity!\n" ));
4888 camera_set_velocity( &tmp, 0 );
4891 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4892 vector tmp = { 0.0f, 0.0f, 0.0f };
4893 camera_set_velocity( &tmp, 0 );
4898 void end_demo_campaign_do()
4900 #if defined(FS2_DEMO)
4901 // show upsell screens
4902 demo_upsell_show_screens();
4903 #elif defined(OEM_BUILD)
4904 // show oem upsell screens
4905 oem_upsell_show_screens();
4908 // drop into main hall
4909 gameseq_post_event( GS_EVENT_MAIN_MENU );
4912 // All code to process events. This is the only place
4913 // that you should change the state of the game.
4914 void game_process_event( int current_state, int event )
4916 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4919 case GS_EVENT_SIMULATOR_ROOM:
4920 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4923 case GS_EVENT_MAIN_MENU:
4924 gameseq_set_state(GS_STATE_MAIN_MENU);
4927 case GS_EVENT_OPTIONS_MENU:
4928 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4931 case GS_EVENT_BARRACKS_MENU:
4932 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4935 case GS_EVENT_TECH_MENU:
4936 gameseq_set_state(GS_STATE_TECH_MENU);
4939 case GS_EVENT_TRAINING_MENU:
4940 gameseq_set_state(GS_STATE_TRAINING_MENU);
4943 case GS_EVENT_START_GAME:
4944 Select_default_ship = 0;
4945 Player_multi_died_check = -1;
4946 gameseq_set_state(GS_STATE_CMD_BRIEF);
4949 case GS_EVENT_START_BRIEFING:
4950 gameseq_set_state(GS_STATE_BRIEFING);
4953 case GS_EVENT_DEBRIEF:
4954 // did we end the campaign in the main freespace 2 single player campaign?
4955 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4956 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4958 gameseq_set_state(GS_STATE_DEBRIEF);
4961 Player_multi_died_check = -1;
4964 case GS_EVENT_SHIP_SELECTION:
4965 gameseq_set_state( GS_STATE_SHIP_SELECT );
4968 case GS_EVENT_WEAPON_SELECTION:
4969 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4972 case GS_EVENT_ENTER_GAME:
4974 // maybe start recording a demo
4976 demo_start_record("test.fsd");
4980 if (Game_mode & GM_MULTIPLAYER) {
4981 // if we're respawning, make sure we change the view mode so that the hud shows up
4982 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4986 gameseq_set_state(GS_STATE_GAME_PLAY);
4988 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4991 Player_multi_died_check = -1;
4993 // clear multiplayer button info
4994 extern button_info Multi_ship_status_bi;
4995 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4997 Start_time = f2fl(timer_get_approx_seconds());
4999 mprintf(("Entering game at time = %7.3f\n", Start_time));
5003 case GS_EVENT_START_GAME_QUICK:
5004 Select_default_ship = 1;
5005 gameseq_post_event(GS_EVENT_ENTER_GAME);
5009 case GS_EVENT_END_GAME:
5010 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5011 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5012 gameseq_set_state(GS_STATE_MAIN_MENU);
5017 Player_multi_died_check = -1;
5020 case GS_EVENT_QUIT_GAME:
5021 main_hall_stop_music();
5022 main_hall_stop_ambient();
5023 gameseq_set_state(GS_STATE_QUIT_GAME);
5025 Player_multi_died_check = -1;
5028 case GS_EVENT_GAMEPLAY_HELP:
5029 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5032 case GS_EVENT_PAUSE_GAME:
5033 gameseq_push_state(GS_STATE_GAME_PAUSED);
5036 case GS_EVENT_DEBUG_PAUSE_GAME:
5037 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5040 case GS_EVENT_TRAINING_PAUSE:
5041 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5044 case GS_EVENT_PREVIOUS_STATE:
5045 gameseq_pop_state();
5048 case GS_EVENT_TOGGLE_FULLSCREEN:
5049 #ifndef HARDWARE_ONLY
5051 if ( gr_screen.mode == GR_SOFTWARE ) {
5052 gr_init( GR_640, GR_DIRECTDRAW );
5053 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5054 gr_init( GR_640, GR_SOFTWARE );
5060 case GS_EVENT_TOGGLE_GLIDE:
5062 if ( gr_screen.mode != GR_GLIDE ) {
5063 gr_init( GR_640, GR_GLIDE );
5065 gr_init( GR_640, GR_SOFTWARE );
5070 case GS_EVENT_LOAD_MISSION_MENU:
5071 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5074 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5075 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5078 case GS_EVENT_HUD_CONFIG:
5079 gameseq_push_state( GS_STATE_HUD_CONFIG );
5082 case GS_EVENT_CONTROL_CONFIG:
5083 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5086 case GS_EVENT_DEATH_DIED:
5087 gameseq_set_state( GS_STATE_DEATH_DIED );
5090 case GS_EVENT_DEATH_BLEW_UP:
5091 if ( current_state == GS_STATE_DEATH_DIED ) {
5092 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5093 event_music_player_death();
5095 // multiplayer clients set their extra check here
5096 if(Game_mode & GM_MULTIPLAYER){
5097 // set the multi died absolute last chance check
5098 Player_multi_died_check = time(NULL);
5101 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5105 case GS_EVENT_NEW_CAMPAIGN:
5106 if (!mission_load_up_campaign()){
5107 readyroom_continue_campaign();
5110 Player_multi_died_check = -1;
5113 case GS_EVENT_CAMPAIGN_CHEAT:
5114 if (!mission_load_up_campaign()){
5116 // bash campaign value
5117 extern char Main_hall_campaign_cheat[512];
5120 // look for the mission
5121 for(idx=0; idx<Campaign.num_missions; idx++){
5122 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5123 Campaign.next_mission = idx;
5124 Campaign.prev_mission = idx - 1;
5131 readyroom_continue_campaign();
5134 Player_multi_died_check = -1;
5137 case GS_EVENT_CAMPAIGN_ROOM:
5138 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5141 case GS_EVENT_CMD_BRIEF:
5142 gameseq_set_state(GS_STATE_CMD_BRIEF);
5145 case GS_EVENT_RED_ALERT:
5146 gameseq_set_state(GS_STATE_RED_ALERT);
5149 case GS_EVENT_CREDITS:
5150 gameseq_set_state( GS_STATE_CREDITS );
5153 case GS_EVENT_VIEW_MEDALS:
5154 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5157 case GS_EVENT_SHOW_GOALS:
5158 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5161 case GS_EVENT_HOTKEY_SCREEN:
5162 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5165 // multiplayer stuff follow these comments
5167 case GS_EVENT_MULTI_JOIN_GAME:
5168 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5171 case GS_EVENT_MULTI_HOST_SETUP:
5172 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5175 case GS_EVENT_MULTI_CLIENT_SETUP:
5176 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5179 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5180 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5183 case GS_EVENT_MULTI_STD_WAIT:
5184 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5187 case GS_EVENT_STANDALONE_MAIN:
5188 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5191 case GS_EVENT_MULTI_PAUSE:
5192 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5195 case GS_EVENT_INGAME_PRE_JOIN:
5196 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5199 case GS_EVENT_EVENT_DEBUG:
5200 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5203 // Start a warpout where player automatically goes 70 no matter what
5204 // and can't cancel out of it.
5205 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5206 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5208 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5209 Player->saved_viewer_mode = Viewer_mode;
5210 Player->control_mode = PCM_WARPOUT_STAGE1;
5211 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5212 Warpout_time = 0.0f; // Start timer!
5215 case GS_EVENT_PLAYER_WARPOUT_START:
5216 if ( Player->control_mode != PCM_NORMAL ) {
5217 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5219 Player->saved_viewer_mode = Viewer_mode;
5220 Player->control_mode = PCM_WARPOUT_STAGE1;
5221 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5222 Warpout_time = 0.0f; // Start timer!
5223 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5227 case GS_EVENT_PLAYER_WARPOUT_STOP:
5228 if ( Player->control_mode != PCM_NORMAL ) {
5229 if ( !Warpout_forced ) { // cannot cancel forced warpout
5230 Player->control_mode = PCM_NORMAL;
5231 Viewer_mode = Player->saved_viewer_mode;
5232 hud_subspace_notify_abort();
5233 mprintf(( "Player put back to normal mode.\n" ));
5234 if ( Warpout_sound > -1 ) {
5235 snd_stop( Warpout_sound );
5242 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5243 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5244 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5245 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5247 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5248 shipfx_warpout_start( Player_obj );
5249 Player->control_mode = PCM_WARPOUT_STAGE2;
5250 Player->saved_viewer_mode = Viewer_mode;
5251 Viewer_mode |= VM_WARP_CHASE;
5253 vector tmp = Player_obj->pos;
5255 ship_get_eye( &tmp, &tmp_m, Player_obj );
5256 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5257 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5258 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5260 camera_set_position( &tmp );
5261 camera_set_orient( &Player_obj->orient );
5262 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5264 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5265 camera_set_velocity( &tmp_vel, 1);
5269 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5270 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5271 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5272 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5274 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5275 Player->control_mode = PCM_WARPOUT_STAGE3;
5279 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5280 mprintf(( "Player warped out. Going to debriefing!\n" ));
5281 Player->control_mode = PCM_NORMAL;
5282 Viewer_mode = Player->saved_viewer_mode;
5285 // we have a special debriefing screen for multiplayer furballs
5286 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5287 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5289 // do the normal debriefing for all other situations
5291 gameseq_post_event(GS_EVENT_DEBRIEF);
5295 case GS_EVENT_STANDALONE_POSTGAME:
5296 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5299 case GS_EVENT_INITIAL_PLAYER_SELECT:
5300 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5303 case GS_EVENT_GAME_INIT:
5304 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5305 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5307 // see if the command line option has been set to use the last pilot, and act acoordingly
5308 if( player_select_get_last_pilot() ) {
5309 // always enter the main menu -- do the automatic network startup stuff elsewhere
5310 // so that we still have valid checks for networking modes, etc.
5311 gameseq_set_state(GS_STATE_MAIN_MENU);
5313 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5318 case GS_EVENT_MULTI_MISSION_SYNC:
5319 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5322 case GS_EVENT_MULTI_START_GAME:
5323 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5326 case GS_EVENT_MULTI_HOST_OPTIONS:
5327 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5330 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5331 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5334 case GS_EVENT_TEAM_SELECT:
5335 gameseq_set_state(GS_STATE_TEAM_SELECT);
5338 case GS_EVENT_END_CAMPAIGN:
5339 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5342 case GS_EVENT_END_DEMO:
5343 gameseq_set_state(GS_STATE_END_DEMO);
5346 case GS_EVENT_LOOP_BRIEF:
5347 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5356 // Called when a state is being left.
5357 // The current state is still at old_state, but as soon as
5358 // this function leaves, then the current state will become
5359 // new state. You should never try to change the state
5360 // in here... if you think you need to, you probably really
5361 // need to post an event, not change the state.
5362 void game_leave_state( int old_state, int new_state )
5364 int end_mission = 1;
5366 switch (new_state) {
5367 case GS_STATE_GAME_PAUSED:
5368 case GS_STATE_DEBUG_PAUSED:
5369 case GS_STATE_OPTIONS_MENU:
5370 case GS_STATE_CONTROL_CONFIG:
5371 case GS_STATE_MISSION_LOG_SCROLLBACK:
5372 case GS_STATE_DEATH_DIED:
5373 case GS_STATE_SHOW_GOALS:
5374 case GS_STATE_HOTKEY_SCREEN:
5375 case GS_STATE_MULTI_PAUSED:
5376 case GS_STATE_TRAINING_PAUSED:
5377 case GS_STATE_EVENT_DEBUG:
5378 case GS_STATE_GAMEPLAY_HELP:
5379 end_mission = 0; // these events shouldn't end a mission
5383 switch (old_state) {
5384 case GS_STATE_BRIEFING:
5385 brief_stop_voices();
5386 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5387 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5388 && (new_state != GS_STATE_TEAM_SELECT) ){
5389 common_select_close();
5390 if ( new_state == GS_STATE_MAIN_MENU ) {
5391 freespace_stop_mission();
5395 // COMMAND LINE OPTION
5396 if (Cmdline_multi_stream_chat_to_file){
5397 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5398 cfclose(Multi_chat_stream);
5402 case GS_STATE_DEBRIEF:
5403 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5408 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5409 multi_df_debrief_close();
5412 case GS_STATE_LOAD_MISSION_MENU:
5413 mission_load_menu_close();
5416 case GS_STATE_SIMULATOR_ROOM:
5420 case GS_STATE_CAMPAIGN_ROOM:
5421 campaign_room_close();
5424 case GS_STATE_CMD_BRIEF:
5425 if (new_state == GS_STATE_OPTIONS_MENU) {
5430 if (new_state == GS_STATE_MAIN_MENU)
5431 freespace_stop_mission();
5436 case GS_STATE_RED_ALERT:
5440 case GS_STATE_SHIP_SELECT:
5441 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_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_WEAPON_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_TEAM_SELECT) {
5455 common_select_close();
5456 if ( new_state == GS_STATE_MAIN_MENU ) {
5457 freespace_stop_mission();
5462 case GS_STATE_TEAM_SELECT:
5463 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5464 new_state != GS_STATE_HOTKEY_SCREEN &&
5465 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5466 common_select_close();
5467 if ( new_state == GS_STATE_MAIN_MENU ) {
5468 freespace_stop_mission();
5473 case GS_STATE_MAIN_MENU:
5474 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5481 case GS_STATE_OPTIONS_MENU:
5482 //game_start_time();
5483 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5484 multi_join_clear_game_list();
5486 options_menu_close();
5489 case GS_STATE_BARRACKS_MENU:
5490 if(new_state != GS_STATE_VIEW_MEDALS){
5495 case GS_STATE_MISSION_LOG_SCROLLBACK:
5496 hud_scrollback_close();
5499 case GS_STATE_TRAINING_MENU:
5500 training_menu_close();
5503 case GS_STATE_GAME_PLAY:
5504 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5505 player_save_target_and_weapon_link_prefs();
5506 game_stop_looped_sounds();
5509 sound_env_disable();
5510 joy_ff_stop_effects();
5512 // stop game time under certain conditions
5513 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5518 // shut down any recording or playing demos
5523 // when in multiplayer and going back to the main menu, send a leave game packet
5524 // right away (before calling stop mission). stop_mission was taking to long to
5525 // close mission down and I want people to get notified ASAP.
5526 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5527 multi_quit_game(PROMPT_NONE);
5530 freespace_stop_mission();
5531 Game_time_compression = F1_0;
5535 case GS_STATE_TECH_MENU:
5539 case GS_STATE_TRAINING_PAUSED:
5540 Training_num_lines = 0;
5541 // fall through to GS_STATE_GAME_PAUSED
5543 case GS_STATE_GAME_PAUSED:
5545 if ( end_mission ) {
5550 case GS_STATE_DEBUG_PAUSED:
5553 pause_debug_close();
5557 case GS_STATE_HUD_CONFIG:
5561 // join/start a game
5562 case GS_STATE_MULTI_JOIN_GAME:
5563 if(new_state != GS_STATE_OPTIONS_MENU){
5564 multi_join_game_close();
5568 case GS_STATE_MULTI_HOST_SETUP:
5569 case GS_STATE_MULTI_CLIENT_SETUP:
5570 // if this is just the host going into the options screen, don't do anything
5571 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5575 // close down the proper state
5576 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5577 multi_create_game_close();
5579 multi_game_client_setup_close();
5582 // COMMAND LINE OPTION
5583 if (Cmdline_multi_stream_chat_to_file){
5584 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5585 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5586 cfclose(Multi_chat_stream);
5591 case GS_STATE_CONTROL_CONFIG:
5592 control_config_close();
5595 case GS_STATE_DEATH_DIED:
5596 Game_mode &= ~GM_DEAD_DIED;
5598 // early end while respawning or blowing up in a multiplayer game
5599 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5601 freespace_stop_mission();
5605 case GS_STATE_DEATH_BLEW_UP:
5606 Game_mode &= ~GM_DEAD_BLEW_UP;
5608 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5609 // to determine if I should do anything.
5610 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5612 freespace_stop_mission();
5615 // if we are not respawing as an observer or as a player, our new state will not
5616 // be gameplay state.
5617 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5618 game_stop_time(); // hasn't been called yet!!
5619 freespace_stop_mission();
5625 case GS_STATE_CREDITS:
5629 case GS_STATE_VIEW_MEDALS:
5633 case GS_STATE_SHOW_GOALS:
5634 mission_show_goals_close();
5637 case GS_STATE_HOTKEY_SCREEN:
5638 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5639 mission_hotkey_close();
5643 case GS_STATE_MULTI_MISSION_SYNC:
5644 // if we're moving into the options menu, don't do anything
5645 if(new_state == GS_STATE_OPTIONS_MENU){
5649 Assert( Game_mode & GM_MULTIPLAYER );
5651 if ( new_state == GS_STATE_GAME_PLAY ){
5652 // palette_restore_palette();
5654 // change a couple of flags to indicate our state!!!
5655 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5656 send_netplayer_update_packet();
5658 // set the game mode
5659 Game_mode |= GM_IN_MISSION;
5663 case GS_STATE_VIEW_CUTSCENES:
5664 cutscenes_screen_close();
5667 case GS_STATE_MULTI_STD_WAIT:
5668 multi_standalone_wait_close();
5671 case GS_STATE_STANDALONE_MAIN:
5672 standalone_main_close();
5673 if(new_state == GS_STATE_MULTI_STD_WAIT){
5674 init_multiplayer_stats();
5678 case GS_STATE_MULTI_PAUSED:
5679 // if ( end_mission ){
5684 case GS_STATE_INGAME_PRE_JOIN:
5685 multi_ingame_select_close();
5688 case GS_STATE_STANDALONE_POSTGAME:
5689 multi_standalone_postgame_close();
5692 case GS_STATE_INITIAL_PLAYER_SELECT:
5693 player_select_close();
5696 case GS_STATE_MULTI_START_GAME:
5697 multi_start_game_close();
5700 case GS_STATE_MULTI_HOST_OPTIONS:
5701 multi_host_options_close();
5704 case GS_STATE_END_OF_CAMPAIGN:
5705 mission_campaign_end_close();
5708 case GS_STATE_LOOP_BRIEF:
5714 // Called when a state is being entered.
5715 // The current state is set to the state we're entering at
5716 // this point, and old_state is set to the state we're coming
5717 // from. You should never try to change the state
5718 // in here... if you think you need to, you probably really
5719 // need to post an event, not change the state.
5721 void game_enter_state( int old_state, int new_state )
5723 switch (new_state) {
5724 case GS_STATE_MAIN_MENU:
5725 // in multiplayer mode, be sure that we are not doing networking anymore.
5726 if ( Game_mode & GM_MULTIPLAYER ) {
5727 Assert( Net_player != NULL );
5728 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5731 Game_time_compression = F1_0;
5733 // determine which ship this guy is currently based on
5734 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5737 if (Player->on_bastion) {
5745 case GS_STATE_BRIEFING:
5746 main_hall_stop_music();
5747 main_hall_stop_ambient();
5749 if (Game_mode & GM_NORMAL) {
5750 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5751 // MWA: or from options or hotkey screens
5752 // JH: or if the command brief state already did this
5753 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5754 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5755 && (old_state != GS_STATE_CMD_BRIEF) ) {
5756 if ( !game_start_mission() ) // this should put us into a new state on failure!
5760 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5761 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5762 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5764 Game_time_compression = F1_0;
5766 if ( red_alert_mission() ) {
5767 gameseq_post_event(GS_EVENT_RED_ALERT);
5774 case GS_STATE_DEBRIEF:
5775 game_stop_looped_sounds();
5776 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5777 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5782 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5783 multi_df_debrief_init();
5786 case GS_STATE_LOAD_MISSION_MENU:
5787 mission_load_menu_init();
5790 case GS_STATE_SIMULATOR_ROOM:
5794 case GS_STATE_CAMPAIGN_ROOM:
5795 campaign_room_init();
5798 case GS_STATE_RED_ALERT:
5799 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5803 case GS_STATE_CMD_BRIEF: {
5804 int team_num = 0; // team number used as index for which cmd brief to use.
5806 if (old_state == GS_STATE_OPTIONS_MENU) {
5810 main_hall_stop_music();
5811 main_hall_stop_ambient();
5813 if (Game_mode & GM_NORMAL) {
5814 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5815 // MWA: or from options or hotkey screens
5816 // JH: or if the command brief state already did this
5817 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5818 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5819 if ( !game_start_mission() ) // this should put us into a new state on failure!
5824 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5825 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5826 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5828 cmd_brief_init(team_num);
5834 case GS_STATE_SHIP_SELECT:
5838 case GS_STATE_WEAPON_SELECT:
5839 weapon_select_init();
5842 case GS_STATE_TEAM_SELECT:
5846 case GS_STATE_GAME_PAUSED:
5851 case GS_STATE_DEBUG_PAUSED:
5852 // game_stop_time();
5853 // os_set_title("FreeSpace - PAUSED");
5856 case GS_STATE_TRAINING_PAUSED:
5863 case GS_STATE_OPTIONS_MENU:
5865 options_menu_init();
5868 case GS_STATE_GAME_PLAY:
5869 // coming from the gameplay state or the main menu, we might need to load the mission
5870 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5871 if ( !game_start_mission() ) // this should put us into a new state.
5876 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5877 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5878 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5879 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5880 (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) ) {
5881 // JAS: Used to do all paging here.
5885 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5889 main_hall_stop_music();
5890 main_hall_stop_ambient();
5891 event_music_first_pattern(); // start the first pattern
5894 // special code that restores player ship selection and weapons loadout when doing a quick start
5895 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5896 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5897 wss_direct_restore_loadout();
5901 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5902 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5903 event_music_first_pattern(); // start the first pattern
5906 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5907 event_music_first_pattern(); // start the first pattern
5909 player_restore_target_and_weapon_link_prefs();
5911 Game_mode |= GM_IN_MISSION;
5914 // required to truely make mouse deltas zeroed in debug mouse code
5915 void mouse_force_pos(int x, int y);
5916 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5921 // only start time if in single player, or coming from multi wait state
5924 (Game_mode & GM_NORMAL) &&
5925 (old_state != GS_STATE_VIEW_CUTSCENES)
5927 (Game_mode & GM_MULTIPLAYER) && (
5928 (old_state == GS_STATE_MULTI_PAUSED) ||
5929 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5935 // when coming from the multi paused state, reset the timestamps
5936 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5937 multi_reset_timestamps();
5940 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5941 // initialize all object update details
5942 multi_oo_gameplay_init();
5945 // under certain circumstances, the server should reset the object update rate limiting stuff
5946 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5947 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5949 // reinitialize the rate limiting system for all clients
5950 multi_oo_rate_init_all();
5953 // multiplayer clients should always re-initialize their control info rate limiting system
5954 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5955 multi_oo_rate_init_all();
5959 if(Game_mode & GM_MULTIPLAYER){
5960 multi_ping_reset_players();
5963 Game_subspace_effect = 0;
5964 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5965 Game_subspace_effect = 1;
5966 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5967 game_start_subspace_ambient_sound();
5971 sound_env_set(&Game_sound_env);
5972 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5974 // clear multiplayer button info i
5975 extern button_info Multi_ship_status_bi;
5976 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5979 case GS_STATE_HUD_CONFIG:
5983 case GS_STATE_MULTI_JOIN_GAME:
5984 multi_join_clear_game_list();
5986 if (old_state != GS_STATE_OPTIONS_MENU) {
5987 multi_join_game_init();
5992 case GS_STATE_MULTI_HOST_SETUP:
5993 // don't reinitialize if we're coming back from the host options screen
5994 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5995 multi_create_game_init();
6000 case GS_STATE_MULTI_CLIENT_SETUP:
6001 if (old_state != GS_STATE_OPTIONS_MENU) {
6002 multi_game_client_setup_init();
6007 case GS_STATE_CONTROL_CONFIG:
6008 control_config_init();
6011 case GS_STATE_TECH_MENU:
6015 case GS_STATE_BARRACKS_MENU:
6016 if(old_state != GS_STATE_VIEW_MEDALS){
6021 case GS_STATE_MISSION_LOG_SCROLLBACK:
6022 hud_scrollback_init();
6025 case GS_STATE_DEATH_DIED:
6026 Player_died_time = timestamp(10);
6028 if(!(Game_mode & GM_MULTIPLAYER)){
6029 player_show_death_message();
6031 Game_mode |= GM_DEAD_DIED;
6034 case GS_STATE_DEATH_BLEW_UP:
6035 if ( !popupdead_is_active() ) {
6036 Player_ai->target_objnum = -1;
6039 // stop any local EMP effect
6042 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6043 Game_mode |= GM_DEAD_BLEW_UP;
6044 Show_viewing_from_self = 0;
6046 // timestamp how long we should wait before displaying the died popup
6047 if ( !popupdead_is_active() ) {
6048 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6052 case GS_STATE_GAMEPLAY_HELP:
6053 gameplay_help_init();
6056 case GS_STATE_CREDITS:
6057 main_hall_stop_music();
6058 main_hall_stop_ambient();
6062 case GS_STATE_VIEW_MEDALS:
6063 medal_main_init(Player);
6066 case GS_STATE_SHOW_GOALS:
6067 mission_show_goals_init();
6070 case GS_STATE_HOTKEY_SCREEN:
6071 mission_hotkey_init();
6074 case GS_STATE_MULTI_MISSION_SYNC:
6075 // if we're coming from the options screen, don't do any
6076 if(old_state == GS_STATE_OPTIONS_MENU){
6080 switch(Multi_sync_mode){
6081 case MULTI_SYNC_PRE_BRIEFING:
6082 // if moving from game forming to the team select state
6085 case MULTI_SYNC_POST_BRIEFING:
6086 // if moving from briefing into the mission itself
6089 // tell everyone that we're now loading data
6090 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6091 send_netplayer_update_packet();
6093 // JAS: Used to do all paging here!!!!
6095 Net_player->state = NETPLAYER_STATE_WAITING;
6096 send_netplayer_update_packet();
6098 Game_time_compression = F1_0;
6100 case MULTI_SYNC_INGAME:
6106 case GS_STATE_VIEW_CUTSCENES:
6107 cutscenes_screen_init();
6110 case GS_STATE_MULTI_STD_WAIT:
6111 multi_standalone_wait_init();
6114 case GS_STATE_STANDALONE_MAIN:
6115 // don't initialize if we're coming from one of these 2 states unless there are no
6116 // players left (reset situation)
6117 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6118 standalone_main_init();
6122 case GS_STATE_MULTI_PAUSED:
6126 case GS_STATE_INGAME_PRE_JOIN:
6127 multi_ingame_select_init();
6130 case GS_STATE_STANDALONE_POSTGAME:
6131 multi_standalone_postgame_init();
6134 case GS_STATE_INITIAL_PLAYER_SELECT:
6135 player_select_init();
6138 case GS_STATE_MULTI_START_GAME:
6139 multi_start_game_init();
6142 case GS_STATE_MULTI_HOST_OPTIONS:
6143 multi_host_options_init();
6146 case GS_STATE_END_OF_CAMPAIGN:
6147 mission_campaign_end_init();
6150 case GS_STATE_LOOP_BRIEF:
6157 // do stuff that may need to be done regardless of state
6158 void game_do_state_common(int state,int no_networking)
6160 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6161 snd_do_frame(); // update sound system
6162 event_music_do_frame(); // music needs to play across many states
6164 multi_log_process();
6166 if (no_networking) {
6170 // maybe do a multiplayer frame based on game mode and state type
6171 if (Game_mode & GM_MULTIPLAYER) {
6173 case GS_STATE_OPTIONS_MENU:
6174 case GS_STATE_GAMEPLAY_HELP:
6175 case GS_STATE_HOTKEY_SCREEN:
6176 case GS_STATE_HUD_CONFIG:
6177 case GS_STATE_CONTROL_CONFIG:
6178 case GS_STATE_MISSION_LOG_SCROLLBACK:
6179 case GS_STATE_SHOW_GOALS:
6180 case GS_STATE_VIEW_CUTSCENES:
6181 case GS_STATE_EVENT_DEBUG:
6182 multi_maybe_do_frame();
6186 game_do_networking();
6190 // Called once a frame.
6191 // You should never try to change the state
6192 // in here... if you think you need to, you probably really
6193 // need to post an event, not change the state.
6194 int Game_do_state_should_skip = 0;
6195 void game_do_state(int state)
6197 // always lets the do_state_common() function determine if the state should be skipped
6198 Game_do_state_should_skip = 0;
6200 // legal to set the should skip state anywhere in this function
6201 game_do_state_common(state); // do stuff that may need to be done regardless of state
6203 if(Game_do_state_should_skip){
6208 case GS_STATE_MAIN_MENU:
6209 game_set_frametime(GS_STATE_MAIN_MENU);
6210 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6213 main_hall_do(flFrametime);
6217 case GS_STATE_OPTIONS_MENU:
6218 game_set_frametime(GS_STATE_OPTIONS_MENU);
6219 options_menu_do_frame(flFrametime);
6222 case GS_STATE_BARRACKS_MENU:
6223 game_set_frametime(GS_STATE_BARRACKS_MENU);
6224 barracks_do_frame(flFrametime);
6227 case GS_STATE_TRAINING_MENU:
6228 game_set_frametime(GS_STATE_TRAINING_MENU);
6229 training_menu_do_frame(flFrametime);
6232 case GS_STATE_TECH_MENU:
6233 game_set_frametime(GS_STATE_TECH_MENU);
6234 techroom_do_frame(flFrametime);
6237 case GS_STATE_GAMEPLAY_HELP:
6238 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6239 gameplay_help_do_frame(flFrametime);
6242 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6246 case GS_STATE_GAME_PAUSED:
6250 case GS_STATE_DEBUG_PAUSED:
6252 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6257 case GS_STATE_TRAINING_PAUSED:
6258 game_training_pause_do();
6261 case GS_STATE_LOAD_MISSION_MENU:
6262 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6263 mission_load_menu_do();
6266 case GS_STATE_BRIEFING:
6267 game_set_frametime(GS_STATE_BRIEFING);
6268 brief_do_frame(flFrametime);
6271 case GS_STATE_DEBRIEF:
6272 game_set_frametime(GS_STATE_DEBRIEF);
6273 debrief_do_frame(flFrametime);
6276 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6277 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6278 multi_df_debrief_do();
6281 case GS_STATE_SHIP_SELECT:
6282 game_set_frametime(GS_STATE_SHIP_SELECT);
6283 ship_select_do(flFrametime);
6286 case GS_STATE_WEAPON_SELECT:
6287 game_set_frametime(GS_STATE_WEAPON_SELECT);
6288 weapon_select_do(flFrametime);
6291 case GS_STATE_MISSION_LOG_SCROLLBACK:
6292 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6293 hud_scrollback_do_frame(flFrametime);
6296 case GS_STATE_HUD_CONFIG:
6297 game_set_frametime(GS_STATE_HUD_CONFIG);
6298 hud_config_do_frame(flFrametime);
6301 case GS_STATE_MULTI_JOIN_GAME:
6302 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6303 multi_join_game_do_frame();
6306 case GS_STATE_MULTI_HOST_SETUP:
6307 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6308 multi_create_game_do();
6311 case GS_STATE_MULTI_CLIENT_SETUP:
6312 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6313 multi_game_client_setup_do_frame();
6316 case GS_STATE_CONTROL_CONFIG:
6317 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6318 control_config_do_frame(flFrametime);
6321 case GS_STATE_DEATH_DIED:
6325 case GS_STATE_DEATH_BLEW_UP:
6329 case GS_STATE_SIMULATOR_ROOM:
6330 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6331 sim_room_do_frame(flFrametime);
6334 case GS_STATE_CAMPAIGN_ROOM:
6335 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6336 campaign_room_do_frame(flFrametime);
6339 case GS_STATE_RED_ALERT:
6340 game_set_frametime(GS_STATE_RED_ALERT);
6341 red_alert_do_frame(flFrametime);
6344 case GS_STATE_CMD_BRIEF:
6345 game_set_frametime(GS_STATE_CMD_BRIEF);
6346 cmd_brief_do_frame(flFrametime);
6349 case GS_STATE_CREDITS:
6350 game_set_frametime(GS_STATE_CREDITS);
6351 credits_do_frame(flFrametime);
6354 case GS_STATE_VIEW_MEDALS:
6355 game_set_frametime(GS_STATE_VIEW_MEDALS);
6359 case GS_STATE_SHOW_GOALS:
6360 game_set_frametime(GS_STATE_SHOW_GOALS);
6361 mission_show_goals_do_frame(flFrametime);
6364 case GS_STATE_HOTKEY_SCREEN:
6365 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6366 mission_hotkey_do_frame(flFrametime);
6369 case GS_STATE_VIEW_CUTSCENES:
6370 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6371 cutscenes_screen_do_frame();
6374 case GS_STATE_MULTI_STD_WAIT:
6375 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6376 multi_standalone_wait_do();
6379 case GS_STATE_STANDALONE_MAIN:
6380 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6381 standalone_main_do();
6384 case GS_STATE_MULTI_PAUSED:
6385 game_set_frametime(GS_STATE_MULTI_PAUSED);
6389 case GS_STATE_TEAM_SELECT:
6390 game_set_frametime(GS_STATE_TEAM_SELECT);
6394 case GS_STATE_INGAME_PRE_JOIN:
6395 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6396 multi_ingame_select_do();
6399 case GS_STATE_EVENT_DEBUG:
6401 game_set_frametime(GS_STATE_EVENT_DEBUG);
6402 game_show_event_debug(flFrametime);
6406 case GS_STATE_STANDALONE_POSTGAME:
6407 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6408 multi_standalone_postgame_do();
6411 case GS_STATE_INITIAL_PLAYER_SELECT:
6412 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6416 case GS_STATE_MULTI_MISSION_SYNC:
6417 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6421 case GS_STATE_MULTI_START_GAME:
6422 game_set_frametime(GS_STATE_MULTI_START_GAME);
6423 multi_start_game_do();
6426 case GS_STATE_MULTI_HOST_OPTIONS:
6427 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6428 multi_host_options_do();
6431 case GS_STATE_END_OF_CAMPAIGN:
6432 mission_campaign_end_do();
6435 case GS_STATE_END_DEMO:
6436 game_set_frametime(GS_STATE_END_DEMO);
6437 end_demo_campaign_do();
6440 case GS_STATE_LOOP_BRIEF:
6441 game_set_frametime(GS_STATE_LOOP_BRIEF);
6445 } // end switch(gs_current_state)
6449 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6450 int game_do_ram_check(int ram_in_bytes)
6452 if ( ram_in_bytes < 30*1024*1024 ) {
6453 int allowed_to_run = 1;
6454 if ( ram_in_bytes < 25*1024*1024 ) {
6459 int Freespace_total_ram_MB;
6460 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6462 if ( allowed_to_run ) {
6464 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);
6468 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6469 if ( msgbox_rval == IDCANCEL ) {
6476 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);
6478 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6489 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6490 // If so, copy it over and remove the update directory.
6491 void game_maybe_update_launcher(char *exe_dir)
6494 char src_filename[MAX_PATH];
6495 char dest_filename[MAX_PATH];
6497 strcpy(src_filename, exe_dir);
6498 strcat(src_filename, NOX("\\update\\freespace.exe"));
6500 strcpy(dest_filename, exe_dir);
6501 strcat(dest_filename, NOX("\\freespace.exe"));
6503 // see if src_filename exists
6505 fp = fopen(src_filename, "rb");
6511 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6513 // copy updated freespace.exe to freespace exe dir
6514 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6515 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 );
6519 // delete the file in the update directory
6520 DeleteFile(src_filename);
6522 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6523 char update_dir[MAX_PATH];
6524 strcpy(update_dir, exe_dir);
6525 strcat(update_dir, NOX("\\update"));
6526 RemoveDirectory(update_dir);
6532 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6536 int sub_total_destroyed = 0;
6540 // get the total for all his children
6541 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6542 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6545 // find the # of faces for this _individual_ object
6546 total = submodel_get_num_polys(model_num, sm);
6547 if(strstr(pm->submodel[sm].name, "-destroyed")){
6548 sub_total_destroyed = total;
6552 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6555 *out_total += total + sub_total;
6556 *out_destroyed_total += sub_total_destroyed;
6559 #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);
6560 void game_spew_pof_info()
6562 char *pof_list[1000];
6565 int idx, model_num, i, j;
6567 int total, root_total, model_total, destroyed_total, counted;
6571 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6573 // spew info on all the pofs
6579 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6584 for(idx=0; idx<num_files; idx++, counted++){
6585 sprintf(str, "%s.pof", pof_list[idx]);
6586 model_num = model_load(str, 0, NULL);
6588 pm = model_get(model_num);
6590 // if we have a real model
6595 // go through and print all raw submodels
6596 cfputs("RAW\n", out);
6599 for (i=0; i<pm->n_models; i++) {
6600 total = submodel_get_num_polys(model_num, i);
6602 model_total += total;
6603 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6606 sprintf(str, "Model total %d\n", model_total);
6609 // now go through and do it by LOD
6610 cfputs("BY LOD\n\n", out);
6611 for(i=0; i<pm->n_detail_levels; i++){
6612 sprintf(str, "LOD %d\n", i);
6616 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6618 destroyed_total = 0;
6619 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6620 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6623 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6626 sprintf(str, "TOTAL: %d\n", total + root_total);
6628 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6630 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6633 cfputs("------------------------------------------------------------------------\n\n", out);
6637 if(counted >= MAX_POLYGON_MODELS - 5){
6650 game_spew_pof_info();
6653 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6658 // Don't let more than one instance of Freespace run.
6659 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6661 SetForegroundWindow(hwnd);
6666 // Find out how much RAM is on this machine
6669 ms.dwLength = sizeof(MEMORYSTATUS);
6670 GlobalMemoryStatus(&ms);
6671 Freespace_total_ram = ms.dwTotalPhys;
6673 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6677 if ( ms.dwTotalVirtual < 1024 ) {
6678 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6682 if (!vm_init(24*1024*1024)) {
6683 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 );
6687 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6689 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);
6699 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6700 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6701 seem worth bothering with.
6705 lResult = RegOpenKeyEx(
6706 HKEY_LOCAL_MACHINE, // Where it is
6707 "Software\\Microsoft\\DirectX", // name of key
6708 NULL, // DWORD reserved
6709 KEY_QUERY_VALUE, // Allows all changes
6710 &hKey // Location to store key
6713 if (lResult == ERROR_SUCCESS) {
6715 DWORD dwType, dwLen;
6718 lResult = RegQueryValueEx(
6719 hKey, // Handle to key
6720 "Version", // The values name
6721 NULL, // DWORD reserved
6722 &dwType, // What kind it is
6723 (ubyte *) version, // value to set
6724 &dwLen // How many bytes to set
6727 if (lResult == ERROR_SUCCESS) {
6728 dx_version = atoi(strstr(version, ".") + 1);
6732 DWORD dwType, dwLen;
6735 lResult = RegQueryValueEx(
6736 hKey, // Handle to key
6737 "InstalledVersion", // The values name
6738 NULL, // DWORD reserved
6739 &dwType, // What kind it is
6740 (ubyte *) &val, // value to set
6741 &dwLen // How many bytes to set
6744 if (lResult == ERROR_SUCCESS) {
6752 if (dx_version < 3) {
6753 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6754 "latest version of DirectX at:\n\n"
6755 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6757 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6758 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6763 //=====================================================
6764 // Make sure we're running in the right directory.
6768 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6769 char *p = exe_dir + strlen(exe_dir);
6771 // chop off the filename
6772 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6778 if ( strlen(exe_dir) > 0 ) {
6779 SetCurrentDirectory(exe_dir);
6782 // check for updated freespace.exe
6783 game_maybe_update_launcher(exe_dir);
6791 extern void windebug_memwatch_init();
6792 windebug_memwatch_init();
6796 parse_cmdline(szCmdLine);
6798 #ifdef STANDALONE_ONLY_BUILD
6800 nprintf(("Network", "Standalone running"));
6803 nprintf(("Network", "Standalone running"));
6811 // maybe spew pof stuff
6812 if(Cmdline_spew_pof_info){
6813 game_spew_pof_info();
6818 // non-demo, non-standalone, play the intro movie
6823 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) ){
6825 #if defined(OEM_BUILD)
6826 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6828 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6829 #endif // defined(OEM_BUILD)
6834 if ( !Is_standalone ) {
6836 // release -- movies always play
6839 // 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
6841 // movie_play( NOX("intro.mve"), 0 );
6843 // debug version, movie will only play with -showmovies
6844 #elif !defined(NDEBUG)
6847 // movie_play( NOX("intro.mve"), 0);
6850 if ( Cmdline_show_movies )
6851 movie_play( NOX("intro.mve"), 0 );
6860 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6862 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6866 // only important for non THREADED mode
6869 state = gameseq_process_events();
6870 if ( state == GS_STATE_QUIT_GAME ){
6877 demo_upsell_show_screens();
6879 #elif defined(OEM_BUILD)
6880 // show upsell screens on exit
6881 oem_upsell_show_screens();
6888 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6894 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6896 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6898 // Do nothing here - RecordExceptionInfo() has already done
6899 // everything that is needed. Actually this code won't even
6900 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6901 // the __except clause.
6907 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6908 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6914 // launcher the fslauncher program on exit
6915 void game_launch_launcher_on_exit()
6919 PROCESS_INFORMATION pi;
6920 char cmd_line[2048];
6921 char original_path[1024] = "";
6923 memset( &si, 0, sizeof(STARTUPINFO) );
6927 _getcwd(original_path, 1023);
6929 // set up command line
6930 strcpy(cmd_line, original_path);
6931 strcat(cmd_line, "\\");
6932 strcat(cmd_line, LAUNCHER_FNAME);
6933 strcat(cmd_line, " -straight_to_update");
6935 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6936 cmd_line, // pointer to command line string
6937 NULL, // pointer to process security attributes
6938 NULL, // pointer to thread security attributes
6939 FALSE, // handle inheritance flag
6940 CREATE_DEFAULT_ERROR_MODE, // creation flags
6941 NULL, // pointer to new environment block
6942 NULL, // pointer to current directory name
6943 &si, // pointer to STARTUPINFO
6944 &pi // pointer to PROCESS_INFORMATION
6946 // to eliminate build warnings
6956 // This function is called when FreeSpace terminates normally.
6958 void game_shutdown(void)
6964 // don't ever flip a page on the standalone!
6965 if(!(Game_mode & GM_STANDALONE_SERVER)){
6971 // if the player has left the "player select" screen and quit the game without actually choosing
6972 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6973 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6977 // load up common multiplayer icons
6978 multi_unload_common_icons();
6980 shockwave_close(); // release any memory used by shockwave system
6981 fireball_close(); // free fireball system
6982 ship_close(); // free any memory that was allocated for the ships
6983 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6984 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6985 bm_unload_all(); // free bitmaps
6986 mission_campaign_close(); // close out the campaign stuff
6987 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6989 #ifdef MULTI_USE_LAG
6993 // the menu close functions will unload the bitmaps if they were displayed during the game
6994 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6997 training_menu_close();
7000 extern void joy_close();
7003 audiostream_close();
7005 event_music_close();
7009 // HACKITY HACK HACK
7010 // if this flag is set, we should be firing up the launcher when exiting freespace
7011 extern int Multi_update_fireup_launcher_on_exit;
7012 if(Multi_update_fireup_launcher_on_exit){
7013 game_launch_launcher_on_exit();
7017 // game_stop_looped_sounds()
7019 // This function will call the appropriate stop looped sound functions for those
7020 // modules which use looping sounds. It is not enough just to stop a looping sound
7021 // at the DirectSound level, the game is keeping track of looping sounds, and this
7022 // function is used to inform the game that looping sounds are being halted.
7024 void game_stop_looped_sounds()
7026 hud_stop_looped_locking_sounds();
7027 hud_stop_looped_engine_sounds();
7028 afterburner_stop_sounds();
7029 player_stop_looped_sounds();
7030 obj_snd_stop_all(); // stop all object-linked persistant sounds
7031 game_stop_subspace_ambient_sound();
7032 snd_stop(Radar_static_looping);
7033 Radar_static_looping = -1;
7034 snd_stop(Target_static_looping);
7035 shipfx_stop_engine_wash_sound();
7036 Target_static_looping = -1;
7039 //////////////////////////////////////////////////////////////////////////
7041 // Code for supporting an animating mouse pointer
7044 //////////////////////////////////////////////////////////////////////////
7046 typedef struct animating_obj
7055 static animating_obj Animating_mouse;
7057 // ----------------------------------------------------------------------------
7058 // init_animating_pointer()
7060 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7061 // gets properly initialized
7063 void init_animating_pointer()
7065 Animating_mouse.first_frame = -1;
7066 Animating_mouse.num_frames = 0;
7067 Animating_mouse.current_frame = -1;
7068 Animating_mouse.time = 0.0f;
7069 Animating_mouse.elapsed_time = 0.0f;
7072 // ----------------------------------------------------------------------------
7073 // load_animating_pointer()
7075 // Called at game init to load in the frames for the animating mouse pointer
7077 // input: filename => filename of animation file that holds the animation
7079 void load_animating_pointer(char *filename, int dx, int dy)
7084 init_animating_pointer();
7086 am = &Animating_mouse;
7087 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7088 if ( am->first_frame == -1 )
7089 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7090 am->current_frame = 0;
7091 am->time = am->num_frames / i2fl(fps);
7094 // ----------------------------------------------------------------------------
7095 // unload_animating_pointer()
7097 // Called at game shutdown to free the memory used to store the animation frames
7099 void unload_animating_pointer()
7104 am = &Animating_mouse;
7105 for ( i = 0; i < am->num_frames; i++ ) {
7106 Assert( (am->first_frame+i) >= 0 );
7107 bm_release(am->first_frame + i);
7110 am->first_frame = -1;
7112 am->current_frame = -1;
7115 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7116 void game_render_mouse(float frametime)
7121 // if animating cursor exists, play the next frame
7122 am = &Animating_mouse;
7123 if ( am->first_frame != -1 ) {
7124 mouse_get_pos(&mx, &my);
7125 am->elapsed_time += frametime;
7126 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7127 if ( am->current_frame >= am->num_frames ) {
7128 am->current_frame = 0;
7129 am->elapsed_time = 0.0f;
7131 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7135 // ----------------------------------------------------------------------------
7136 // game_maybe_draw_mouse()
7138 // determines whether to draw the mouse pointer at all, and what frame of
7139 // animation to use if the mouse is animating
7141 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7143 // input: frametime => elapsed frame time in seconds since last call
7145 void game_maybe_draw_mouse(float frametime)
7149 game_state = gameseq_get_state();
7151 switch ( game_state ) {
7152 case GS_STATE_GAME_PAUSED:
7153 // case GS_STATE_MULTI_PAUSED:
7154 case GS_STATE_GAME_PLAY:
7155 case GS_STATE_DEATH_DIED:
7156 case GS_STATE_DEATH_BLEW_UP:
7157 if ( popup_active() || popupdead_is_active() ) {
7169 if ( !Mouse_hidden )
7170 game_render_mouse(frametime);
7174 void game_do_training_checks()
7178 waypoint_list *wplp;
7180 if (Training_context & TRAINING_CONTEXT_SPEED) {
7181 s = (int) Player_obj->phys_info.fspeed;
7182 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7183 if (!Training_context_speed_set) {
7184 Training_context_speed_set = 1;
7185 Training_context_speed_timestamp = timestamp();
7189 Training_context_speed_set = 0;
7192 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7193 wplp = &Waypoint_lists[Training_context_path];
7194 if (wplp->count > Training_context_goal_waypoint) {
7195 i = Training_context_goal_waypoint;
7197 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7198 if (d <= Training_context_distance) {
7199 Training_context_at_waypoint = i;
7200 if (Training_context_goal_waypoint == i) {
7201 Training_context_goal_waypoint++;
7202 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7209 if (i == wplp->count)
7212 } while (i != Training_context_goal_waypoint);
7216 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7217 Players_target = Player_ai->target_objnum;
7218 Players_targeted_subsys = Player_ai->targeted_subsys;
7219 Players_target_timestamp = timestamp();
7223 /////////// Following is for event debug view screen
7227 #define EVENT_DEBUG_MAX 5000
7228 #define EVENT_DEBUG_EVENT 0x8000
7230 int Event_debug_index[EVENT_DEBUG_MAX];
7233 void game_add_event_debug_index(int n, int indent)
7235 if (ED_count < EVENT_DEBUG_MAX)
7236 Event_debug_index[ED_count++] = n | (indent << 16);
7239 void game_add_event_debug_sexp(int n, int indent)
7244 if (Sexp_nodes[n].first >= 0) {
7245 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7246 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7250 game_add_event_debug_index(n, indent);
7251 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7252 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7254 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7257 void game_event_debug_init()
7262 for (e=0; e<Num_mission_events; e++) {
7263 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7264 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7268 void game_show_event_debug(float frametime)
7272 int font_height, font_width;
7274 static int scroll_offset = 0;
7276 k = game_check_key();
7282 if (scroll_offset < 0)
7292 scroll_offset -= 20;
7293 if (scroll_offset < 0)
7298 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7302 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7308 gr_set_color_fast(&Color_bright);
7310 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7312 gr_set_color_fast(&Color_normal);
7314 gr_get_string_size(&font_width, &font_height, NOX("test"));
7315 y_max = gr_screen.max_h - font_height - 5;
7319 while (k < ED_count) {
7320 if (y_index > y_max)
7323 z = Event_debug_index[k];
7324 if (z & EVENT_DEBUG_EVENT) {
7326 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7327 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7328 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7329 Mission_events[z].repeat_count, Mission_events[z].interval);
7337 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7338 switch (Sexp_nodes[z & 0x7fff].value) {
7340 strcat(buf, NOX(" (True)"));
7344 strcat(buf, NOX(" (False)"));
7347 case SEXP_KNOWN_TRUE:
7348 strcat(buf, NOX(" (Always true)"));
7351 case SEXP_KNOWN_FALSE:
7352 strcat(buf, NOX(" (Always false)"));
7355 case SEXP_CANT_EVAL:
7356 strcat(buf, NOX(" (Can't eval)"));
7360 case SEXP_NAN_FOREVER:
7361 strcat(buf, NOX(" (Not a number)"));
7366 gr_printf(10, y_index, buf);
7367 y_index += font_height;
7380 extern int Tmap_npixels;
7382 int Tmap_num_too_big = 0;
7383 int Num_models_needing_splitting = 0;
7385 void Time_model( int modelnum )
7387 // mprintf(( "Timing ship '%s'\n", si->name ));
7389 vector eye_pos, model_pos;
7390 matrix eye_orient, model_orient;
7392 polymodel *pm = model_get( modelnum );
7394 int l = strlen(pm->filename);
7396 if ( (l == '/') || (l=='\\') || (l==':')) {
7402 char *pof_file = &pm->filename[l];
7404 int model_needs_splitting = 0;
7406 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7408 for (i=0; i<pm->n_textures; i++ ) {
7409 char filename[1024];
7412 int bmp_num = pm->original_textures[i];
7413 if ( bmp_num > -1 ) {
7414 bm_get_palette(pm->original_textures[i], pal, filename );
7416 bm_get_info( pm->original_textures[i],&w, &h );
7419 if ( (w > 512) || (h > 512) ) {
7420 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7422 model_needs_splitting++;
7425 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7429 if ( model_needs_splitting ) {
7430 Num_models_needing_splitting++;
7432 eye_orient = model_orient = vmd_identity_matrix;
7433 eye_pos = model_pos = vmd_zero_vector;
7435 eye_pos.z = -pm->rad*2.0f;
7437 vector eye_to_model;
7439 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7440 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7442 fix t1 = timer_get_fixed_seconds();
7445 ta.p = ta.b = ta.h = 0.0f;
7450 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7452 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7454 modelstats_num_polys = modelstats_num_verts = 0;
7456 while( ta.h < PI2 ) {
7459 vm_angles_2_matrix(&m1, &ta );
7460 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7467 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7469 model_clear_instance( modelnum );
7470 model_set_detail_level(0); // use highest detail level
7471 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7479 int k = key_inkey();
7480 if ( k == KEY_ESC ) {
7485 fix t2 = timer_get_fixed_seconds();
7487 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7488 //bitmaps_used_this_frame /= framecount;
7490 modelstats_num_polys /= framecount;
7491 modelstats_num_verts /= framecount;
7493 Tmap_npixels /=framecount;
7496 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7497 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 );
7498 // 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 );
7504 int Time_models = 0;
7505 DCF_BOOL( time_models, Time_models );
7507 void Do_model_timings_test()
7511 if ( !Time_models ) return;
7513 mprintf(( "Timing models!\n" ));
7517 ubyte model_used[MAX_POLYGON_MODELS];
7518 int model_id[MAX_POLYGON_MODELS];
7519 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7524 for (i=0; i<Num_ship_types; i++ ) {
7525 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7527 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7528 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7531 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7532 if ( !Texture_fp ) return;
7534 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7535 if ( !Time_fp ) return;
7537 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7538 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7540 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7541 if ( model_used[i] ) {
7542 Time_model( model_id[i] );
7546 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7547 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7556 // Call this function when you want to inform the player that a feature is not
7557 // enabled in the DEMO version of FreSpace
7558 void game_feature_not_in_demo_popup()
7560 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7563 // format the specified time (fixed point) into a nice string
7564 void game_format_time(fix m_time,char *time_str)
7567 int hours,minutes,seconds;
7570 mtime = f2fl(m_time);
7572 // get the hours, minutes and seconds
7573 hours = (int)(mtime / 3600.0f);
7575 mtime -= (3600.0f * (float)hours);
7577 seconds = (int)mtime%60;
7578 minutes = (int)mtime/60;
7580 // print the hour if necessary
7582 sprintf(time_str,XSTR( "%d:", 201),hours);
7583 // if there are less than 10 minutes, print a leading 0
7585 strcpy(tmp,NOX("0"));
7586 strcat(time_str,tmp);
7590 // print the minutes
7592 sprintf(tmp,XSTR( "%d:", 201),minutes);
7593 strcat(time_str,tmp);
7595 sprintf(time_str,XSTR( "%d:", 201),minutes);
7598 // print the seconds
7600 strcpy(tmp,NOX("0"));
7601 strcat(time_str,tmp);
7603 sprintf(tmp,"%d",seconds);
7604 strcat(time_str,tmp);
7607 // Stuff version string in *str.
7608 void get_version_string(char *str)
7611 if ( FS_VERSION_BUILD == 0 ) {
7612 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7614 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7617 #if defined (FS2_DEMO)
7619 #elif defined (OEM_BUILD)
7620 strcat(str, " (OEM)");
7626 char myname[_MAX_PATH];
7627 int namelen, major, minor, build, waste;
7628 unsigned int buf_size;
7634 // Find my EXE file name
7635 hMod = GetModuleHandle(NULL);
7636 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7638 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7639 infop = (char *)malloc(version_size);
7640 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7642 // get the product version
7643 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7644 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7646 sprintf(str,"Dv%d.%02d",major, minor);
7648 sprintf(str,"v%d.%02d",major, minor);
7653 void get_version_string_short(char *str)
7655 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7658 // ----------------------------------------------------------------
7660 // OEM UPSELL SCREENS BEGIN
7662 // ----------------------------------------------------------------
7663 #if defined(OEM_BUILD)
7665 #define NUM_OEM_UPSELL_SCREENS 3
7666 #define OEM_UPSELL_SCREEN_DELAY 10000
7668 static int Oem_upsell_bitmaps_loaded = 0;
7669 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7670 static int Oem_upsell_screen_number = 0;
7671 static int Oem_upsell_show_next_bitmap_time;
7674 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7687 static int Oem_normal_cursor = -1;
7688 static int Oem_web_cursor = -1;
7689 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7690 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7692 void oem_upsell_next_screen()
7694 Oem_upsell_screen_number++;
7695 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7696 // extra long delay, mouse shown on last upsell
7697 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7701 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7705 void oem_upsell_load_bitmaps()
7709 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7710 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7714 void oem_upsell_unload_bitmaps()
7718 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7719 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7720 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7725 Oem_upsell_bitmaps_loaded = 0;
7728 // clickable hotspot on 3rd OEM upsell screen
7729 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7731 28, 350, 287, 96 // x, y, w, h
7734 45, 561, 460, 152 // x, y, w, h
7738 void oem_upsell_show_screens()
7740 int current_time, k;
7743 if ( !Oem_upsell_bitmaps_loaded ) {
7744 oem_upsell_load_bitmaps();
7745 Oem_upsell_bitmaps_loaded = 1;
7748 // may use upsell screens more than once
7749 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7750 Oem_upsell_screen_number = 0;
7756 int nframes; // used to pass, not really needed (should be 1)
7757 Oem_normal_cursor = gr_get_cursor_bitmap();
7758 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7759 Assert(Oem_web_cursor >= 0);
7760 if (Oem_web_cursor < 0) {
7761 Oem_web_cursor = Oem_normal_cursor;
7766 //oem_reset_trailer_timer();
7768 current_time = timer_get_milliseconds();
7773 // advance screen on keypress or timeout
7774 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7775 oem_upsell_next_screen();
7778 // check if we are done
7779 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7780 Oem_upsell_screen_number--;
7783 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7788 // show me the upsell
7789 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7790 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7794 // if this is the 3rd upsell, make it clickable, d00d
7795 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7797 int button_state = mouse_get_pos(&mx, &my);
7798 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])
7799 && (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]) )
7802 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7805 if (button_state & MOUSE_LEFT_BUTTON) {
7807 multi_pxo_url(OEM_UPSELL_URL);
7811 // switch cursor back to normal one
7812 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7817 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7827 oem_upsell_unload_bitmaps();
7829 // switch cursor back to normal one
7830 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7834 #endif // defined(OEM_BUILD)
7835 // ----------------------------------------------------------------
7837 // OEM UPSELL SCREENS END
7839 // ----------------------------------------------------------------
7843 // ----------------------------------------------------------------
7845 // DEMO UPSELL SCREENS BEGIN
7847 // ----------------------------------------------------------------
7851 //#define NUM_DEMO_UPSELL_SCREENS 4
7853 #define NUM_DEMO_UPSELL_SCREENS 2
7854 #define DEMO_UPSELL_SCREEN_DELAY 3000
7856 static int Demo_upsell_bitmaps_loaded = 0;
7857 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7858 static int Demo_upsell_screen_number = 0;
7859 static int Demo_upsell_show_next_bitmap_time;
7862 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7875 void demo_upsell_next_screen()
7877 Demo_upsell_screen_number++;
7878 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7879 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7881 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7885 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7886 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7887 #ifndef HARDWARE_ONLY
7888 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7895 void demo_upsell_load_bitmaps()
7899 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7900 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7904 void demo_upsell_unload_bitmaps()
7908 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7909 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7910 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7915 Demo_upsell_bitmaps_loaded = 0;
7918 void demo_upsell_show_screens()
7920 int current_time, k;
7923 if ( !Demo_upsell_bitmaps_loaded ) {
7924 demo_upsell_load_bitmaps();
7925 Demo_upsell_bitmaps_loaded = 1;
7928 // may use upsell screens more than once
7929 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7930 Demo_upsell_screen_number = 0;
7937 demo_reset_trailer_timer();
7939 current_time = timer_get_milliseconds();
7946 // don't time out, wait for keypress
7948 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7949 demo_upsell_next_screen();
7954 demo_upsell_next_screen();
7957 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7958 Demo_upsell_screen_number--;
7961 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7966 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7967 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7972 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7982 demo_upsell_unload_bitmaps();
7987 // ----------------------------------------------------------------
7989 // DEMO UPSELL SCREENS END
7991 // ----------------------------------------------------------------
7994 // ----------------------------------------------------------------
7996 // Subspace Ambient Sound START
7998 // ----------------------------------------------------------------
8000 static int Subspace_ambient_left_channel = -1;
8001 static int Subspace_ambient_right_channel = -1;
8004 void game_start_subspace_ambient_sound()
8006 if ( Subspace_ambient_left_channel < 0 ) {
8007 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8010 if ( Subspace_ambient_right_channel < 0 ) {
8011 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8015 void game_stop_subspace_ambient_sound()
8017 if ( Subspace_ambient_left_channel >= 0 ) {
8018 snd_stop(Subspace_ambient_left_channel);
8019 Subspace_ambient_left_channel = -1;
8022 if ( Subspace_ambient_right_channel >= 0 ) {
8023 snd_stop(Subspace_ambient_right_channel);
8024 Subspace_ambient_right_channel = -1;
8028 // ----------------------------------------------------------------
8030 // Subspace Ambient Sound END
8032 // ----------------------------------------------------------------
8034 // ----------------------------------------------------------------
8036 // CDROM detection code START
8038 // ----------------------------------------------------------------
8040 #define CD_SIZE_72_MINUTE_MAX (697000000)
8042 uint game_get_cd_used_space(char *path)
8046 char use_path[512] = "";
8047 char sub_path[512] = "";
8048 WIN32_FIND_DATA find;
8051 // recurse through all files and directories
8052 strcpy(use_path, path);
8053 strcat(use_path, "*.*");
8054 find_handle = FindFirstFile(use_path, &find);
8057 if(find_handle == INVALID_HANDLE_VALUE){
8063 // subdirectory. make sure to ignore . and ..
8064 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8066 strcpy(sub_path, path);
8067 strcat(sub_path, find.cFileName);
8068 strcat(sub_path, "\\");
8069 total += game_get_cd_used_space(sub_path);
8071 total += (uint)find.nFileSizeLow;
8073 } while(FindNextFile(find_handle, &find));
8076 FindClose(find_handle);
8088 // if volume_name is non-null, the CD name must match that
8089 int find_freespace_cd(char *volume_name)
8092 char oldpath[MAX_PATH];
8096 int volume_match = 0;
8100 GetCurrentDirectory(MAX_PATH, oldpath);
8102 for (i = 0; i < 26; i++)
8108 path[0] = (char)('A'+i);
8109 if (GetDriveType(path) == DRIVE_CDROM) {
8111 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8112 nprintf(("CD", "CD volume: %s\n", volume));
8114 // check for any CD volume
8115 int volume1_present = 0;
8116 int volume2_present = 0;
8117 int volume3_present = 0;
8119 char full_check[512] = "";
8121 // look for setup.exe
8122 strcpy(full_check, path);
8123 strcat(full_check, "setup.exe");
8124 find_handle = _findfirst(full_check, &find);
8125 if(find_handle != -1){
8126 volume1_present = 1;
8127 _findclose(find_handle);
8130 // look for intro.mve
8131 strcpy(full_check, path);
8132 strcat(full_check, "intro.mve");
8133 find_handle = _findfirst(full_check, &find);
8134 if(find_handle != -1){
8135 volume2_present = 1;
8136 _findclose(find_handle);
8139 // look for endpart1.mve
8140 strcpy(full_check, path);
8141 strcat(full_check, "endpart1.mve");
8142 find_handle = _findfirst(full_check, &find);
8143 if(find_handle != -1){
8144 volume3_present = 1;
8145 _findclose(find_handle);
8148 // see if we have the specific CD we're looking for
8149 if ( volume_name ) {
8151 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8155 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8159 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8163 if ( volume1_present || volume2_present || volume3_present ) {
8168 // 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
8169 if ( volume_match ){
8171 // 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
8172 if(volume2_present || volume3_present) {
8173 // first step - check to make sure its a cdrom
8174 if(GetDriveType(path) != DRIVE_CDROM){
8178 #if !defined(OEM_BUILD)
8179 // oem not on 80 min cds, so dont check tha size
8181 uint used_space = game_get_cd_used_space(path);
8182 if(used_space < CD_SIZE_72_MINUTE_MAX){
8185 #endif // !defined(OEM_BUILD)
8193 #endif // RELEASE_REAL
8199 SetCurrentDirectory(oldpath);
8208 int set_cdrom_path(int drive_num)
8212 if (drive_num < 0) { //no CD
8214 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8217 strcpy(Game_CDROM_dir,""); //set directory
8221 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8237 i = find_freespace_cd();
8239 rval = set_cdrom_path(i);
8243 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8245 nprintf(("CD", "FreeSpace CD not found\n"));
8253 int Last_cd_label_found = 0;
8254 char Last_cd_label[256];
8256 int game_cd_changed()
8263 if ( strlen(Game_CDROM_dir) == 0 ) {
8267 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8269 if ( found != Last_cd_label_found ) {
8270 Last_cd_label_found = found;
8272 mprintf(( "CD '%s' was inserted\n", label ));
8275 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8279 if ( Last_cd_label_found ) {
8280 if ( !stricmp( Last_cd_label, label )) {
8281 //mprintf(( "CD didn't change\n" ));
8283 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8287 // none found before, none found now.
8288 //mprintf(( "still no CD...\n" ));
8292 Last_cd_label_found = found;
8294 strcpy( Last_cd_label, label );
8296 strcpy( Last_cd_label, "" );
8307 // check if _any_ FreeSpace2 CDs are in the drive
8308 // return: 1 => CD now in drive
8309 // 0 => Could not find CD, they refuse to put it in the drive
8310 int game_do_cd_check(char *volume_name)
8312 #if !defined(GAME_CD_CHECK)
8318 int num_attempts = 0;
8319 int refresh_files = 0;
8321 int path_set_ok, popup_rval;
8323 cd_drive_num = find_freespace_cd(volume_name);
8324 path_set_ok = set_cdrom_path(cd_drive_num);
8325 if ( path_set_ok ) {
8327 if ( refresh_files ) {
8339 // no CD found, so prompt user
8340 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8342 if ( popup_rval != 1 ) {
8347 if ( num_attempts++ > 5 ) {
8358 // check if _any_ FreeSpace2 CDs are in the drive
8359 // return: 1 => CD now in drive
8360 // 0 => Could not find CD, they refuse to put it in the drive
8361 int game_do_cd_check_specific(char *volume_name, int cdnum)
8366 int num_attempts = 0;
8367 int refresh_files = 0;
8369 int path_set_ok, popup_rval;
8371 cd_drive_num = find_freespace_cd(volume_name);
8372 path_set_ok = set_cdrom_path(cd_drive_num);
8373 if ( path_set_ok ) {
8375 if ( refresh_files ) {
8386 // no CD found, so prompt user
8387 #if defined(DVD_MESSAGE_HACK)
8388 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8390 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8393 if ( popup_rval != 1 ) {
8398 if ( num_attempts++ > 5 ) {
8408 // only need to do this in RELEASE_REAL
8409 int game_do_cd_mission_check(char *filename)
8415 fs_builtin_mission *m = game_find_builtin_mission(filename);
8417 // check for changed CD
8418 if(game_cd_changed()){
8423 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8427 // not builtin, so do a general check (any FS2 CD will do)
8429 return game_do_cd_check();
8432 // does not have any CD requirement, do a general check
8433 if(strlen(m->cd_volume) <= 0){
8434 return game_do_cd_check();
8438 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8440 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8442 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8445 return game_do_cd_check();
8448 // did we find the cd?
8449 if(find_freespace_cd(m->cd_volume) >= 0){
8453 // make sure the volume exists
8454 int num_attempts = 0;
8455 int refresh_files = 0;
8457 int path_set_ok, popup_rval;
8459 cd_drive_num = find_freespace_cd(m->cd_volume);
8460 path_set_ok = set_cdrom_path(cd_drive_num);
8461 if ( path_set_ok ) {
8463 if ( refresh_files ) {
8470 // no CD found, so prompt user
8471 #if defined(DVD_MESSAGE_HACK)
8472 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8474 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8478 if ( popup_rval != 1 ) {
8483 if ( num_attempts++ > 5 ) {
8495 // ----------------------------------------------------------------
8497 // CDROM detection code END
8499 // ----------------------------------------------------------------
8501 // ----------------------------------------------------------------
8502 // SHIPS TBL VERIFICATION STUFF
8505 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8506 #define NUM_SHIPS_TBL_CHECKSUMS 1
8508 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8509 -463907578, // US - beta 1
8510 1696074201, // FS2 demo
8513 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8514 // -1022810006, // 1.0 FULL
8515 -1254285366 // 1.2 FULL (German)
8518 void verify_ships_tbl()
8522 Game_ships_tbl_valid = 1;
8528 // detect if the packfile exists
8529 CFILE *detect = cfopen("ships.tbl", "rb");
8530 Game_ships_tbl_valid = 0;
8534 Game_ships_tbl_valid = 0;
8538 // get the long checksum of the file
8540 cfseek(detect, 0, SEEK_SET);
8541 cf_chksum_long(detect, &file_checksum);
8545 // now compare the checksum/filesize against known #'s
8546 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8547 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8548 Game_ships_tbl_valid = 1;
8555 DCF(shipspew, "display the checksum for the current ships.tbl")
8558 CFILE *detect = cfopen("ships.tbl", "rb");
8559 // get the long checksum of the file
8561 cfseek(detect, 0, SEEK_SET);
8562 cf_chksum_long(detect, &file_checksum);
8565 dc_printf("%d", file_checksum);
8568 // ----------------------------------------------------------------
8569 // WEAPONS TBL VERIFICATION STUFF
8572 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8573 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8575 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8576 141718090, // US - beta 1
8577 -266420030, // demo 1
8580 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8581 // 399297860, // 1.0 FULL
8582 -553984927 // 1.2 FULL (german)
8585 void verify_weapons_tbl()
8589 Game_weapons_tbl_valid = 1;
8595 // detect if the packfile exists
8596 CFILE *detect = cfopen("weapons.tbl", "rb");
8597 Game_weapons_tbl_valid = 0;
8601 Game_weapons_tbl_valid = 0;
8605 // get the long checksum of the file
8607 cfseek(detect, 0, SEEK_SET);
8608 cf_chksum_long(detect, &file_checksum);
8612 // now compare the checksum/filesize against known #'s
8613 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8614 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8615 Game_weapons_tbl_valid = 1;
8622 DCF(wepspew, "display the checksum for the current weapons.tbl")
8625 CFILE *detect = cfopen("weapons.tbl", "rb");
8626 // get the long checksum of the file
8628 cfseek(detect, 0, SEEK_SET);
8629 cf_chksum_long(detect, &file_checksum);
8632 dc_printf("%d", file_checksum);
8635 // if the game is running using hacked data
8636 int game_hacked_data()
8639 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8647 void display_title_screen()
8649 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8650 ///int title_bitmap;
8653 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8654 if (title_bitmap == -1) {
8659 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8660 extern void d3d_start_frame();
8665 gr_set_bitmap(title_bitmap);
8671 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8672 extern void d3d_stop_frame();
8679 bm_unload(title_bitmap);
8680 #endif // FS2_DEMO || OEM_BUILD
8683 // return true if the game is running with "low memory", which is less than 48MB
8684 bool game_using_low_mem()
8686 if (Use_low_mem == 0) {