2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.2 2002/05/07 03:16:44 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:09 root
17 * 201 6/16/00 3:15p Jefff
18 * sim of the year dvd version changes, a few german soty localization
21 * 200 11/03/99 11:06a Jefff
24 * 199 10/26/99 5:07p Jamest
25 * fixed jeffs dumb debug code
27 * 198 10/25/99 5:53p Jefff
28 * call control_config_common_init() on startup
30 * 197 10/14/99 10:18a Daveb
31 * Fixed incorrect CD checking problem on standalone server.
33 * 196 10/13/99 9:22a Daveb
34 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
35 * related to movies. Fixed launcher spawning from PXO screen.
37 * 195 10/06/99 11:05a Jefff
38 * new oem upsell 3 hotspot coords
40 * 194 10/06/99 10:31a Jefff
43 * 193 10/01/99 9:10a Daveb
46 * 192 9/15/99 4:57a Dave
47 * Updated ships.tbl checksum
49 * 191 9/15/99 3:58a Dave
50 * Removed framerate warning at all times.
52 * 190 9/15/99 3:16a Dave
53 * Remove mt-011.fs2 from the builtin mission list.
55 * 189 9/15/99 1:45a Dave
56 * Don't init joystick on standalone. Fixed campaign mode on standalone.
57 * Fixed no-score-report problem in TvT
59 * 188 9/14/99 6:08a Dave
60 * Updated (final) single, multi, and campaign list.
62 * 187 9/14/99 3:26a Dave
63 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
64 * respawn-too-early problem. Made a few crash points safe.
66 * 186 9/13/99 4:52p Dave
69 * 185 9/12/99 8:09p Dave
70 * Fixed problem where skip-training button would cause mission messages
71 * not to get paged out for the current mission.
73 * 184 9/10/99 11:53a Dave
74 * Shutdown graphics before sound to eliminate apparent lockups when
75 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
77 * 183 9/09/99 11:40p Dave
78 * Handle an Assert() in beam code. Added supernova sounds. Play the right
79 * 2 end movies properly, based upon what the player did in the mission.
81 * 182 9/08/99 10:29p Dave
82 * Make beam sound pausing and unpausing much safer.
84 * 181 9/08/99 10:01p Dave
85 * Make sure game won't run in a drive's root directory. Make sure
86 * standalone routes suqad war messages properly to the host.
88 * 180 9/08/99 3:22p Dave
89 * Updated builtin mission list.
91 * 179 9/08/99 12:01p Jefff
92 * fixed Game_builtin_mission_list typo on Training-2.fs2
94 * 178 9/08/99 9:48a Andsager
95 * Add force feedback for engine wash.
97 * 177 9/07/99 4:01p Dave
98 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
99 * does everything properly (setting up address when binding). Remove
100 * black rectangle background from UI_INPUTBOX.
102 * 176 9/13/99 2:40a Dave
103 * Comment in full 80 minute CD check for RELEASE_REAL builds.
105 * 175 9/06/99 6:38p Dave
106 * Improved CD detection code.
108 * 174 9/06/99 1:30a Dave
109 * Intermediate checkin. Started on enforcing CD-in-drive to play the
112 * 173 9/06/99 1:16a Dave
113 * Make sure the user sees the intro movie.
115 * 172 9/04/99 8:00p Dave
116 * Fixed up 1024 and 32 bit movie support.
118 * 171 9/03/99 1:32a Dave
119 * CD checking by act. Added support to play 2 cutscenes in a row
120 * seamlessly. Fixed super low level cfile bug related to files in the
121 * root directory of a CD. Added cheat code to set campaign mission # in
124 * 170 9/01/99 10:49p Dave
125 * Added nice SquadWar checkbox to the client join wait screen.
127 * 169 9/01/99 10:14a Dave
130 * 168 8/29/99 4:51p Dave
131 * Fixed damaged checkin.
133 * 167 8/29/99 4:18p Andsager
134 * New "burst" limit for friendly damage. Also credit more damage done
135 * against large friendly ships.
137 * 166 8/27/99 6:38p Alanl
138 * crush the blasted repeating messages bug
140 * 164 8/26/99 9:09p Dave
141 * Force framerate check in everything but a RELEASE_REAL build.
143 * 163 8/26/99 9:45a Dave
144 * First pass at easter eggs and cheats.
146 * 162 8/24/99 8:55p Dave
147 * Make sure nondimming pixels work properly in tech menu.
149 * 161 8/24/99 1:49a Dave
150 * Fixed client-side afterburner stuttering. Added checkbox for no version
151 * checking on PXO join. Made button info passing more friendly between
154 * 160 8/22/99 5:53p Dave
155 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
156 * instead of ship designations for multiplayer players.
158 * 159 8/22/99 1:19p Dave
159 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
160 * which d3d cards are detected.
162 * 158 8/20/99 2:09p Dave
163 * PXO banner cycling.
165 * 157 8/19/99 10:59a Dave
166 * Packet loss detection.
168 * 156 8/19/99 10:12a Alanl
169 * preload mission-specific messages on machines greater than 48MB
171 * 155 8/16/99 4:04p Dave
172 * Big honking checkin.
174 * 154 8/11/99 5:54p Dave
175 * Fixed collision problem. Fixed standalone ghost problem.
177 * 153 8/10/99 7:59p Jefff
180 * 152 8/10/99 6:54p Dave
181 * Mad optimizations. Added paging to the nebula effect.
183 * 151 8/10/99 3:44p Jefff
184 * loads Intelligence information on startup
186 * 150 8/09/99 3:47p Dave
187 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
188 * non-nebula missions.
190 * 149 8/09/99 2:21p Andsager
191 * Fix patching from multiplayer direct to launcher update tab.
193 * 148 8/09/99 10:36a Dave
194 * Version info for game.
196 * 147 8/06/99 9:46p Dave
197 * Hopefully final changes for the demo.
199 * 146 8/06/99 3:34p Andsager
200 * Make title version info "(D)" -> "D" show up nicely
202 * 145 8/06/99 2:59p Adamp
203 * Fixed NT launcher/update problem.
205 * 144 8/06/99 1:52p Dave
206 * Bumped up MAX_BITMAPS for the demo.
208 * 143 8/06/99 12:17p Andsager
209 * Demo: down to just 1 demo dog
211 * 142 8/05/99 9:39p Dave
212 * Yet another new checksum.
214 * 141 8/05/99 6:19p Dave
215 * New demo checksums.
217 * 140 8/05/99 5:31p Andsager
218 * Up demo version 1.01
220 * 139 8/05/99 4:22p Andsager
221 * No time limit on upsell screens. Reverse order of display of upsell
224 * 138 8/05/99 4:17p Dave
225 * Tweaks to client interpolation.
227 * 137 8/05/99 3:52p Danw
229 * 136 8/05/99 3:01p Danw
231 * 135 8/05/99 2:43a Anoop
232 * removed duplicate definition.
234 * 134 8/05/99 2:13a Dave
237 * 133 8/05/99 2:05a Dave
240 * 132 8/05/99 1:22a Andsager
243 * 131 8/04/99 9:51p Andsager
244 * Add title screen to demo
246 * 130 8/04/99 6:47p Jefff
247 * fixed link error resulting from #ifdefs
249 * 129 8/04/99 6:26p Dave
250 * Updated ship tbl checksum.
252 * 128 8/04/99 5:40p Andsager
253 * Add multiple demo dogs
255 * 127 8/04/99 5:36p Andsager
256 * Show upsell screens at end of demo campaign before returning to main
259 * 126 8/04/99 11:42a Danw
260 * tone down EAX reverb
262 * 125 8/04/99 11:23a Dave
263 * Updated demo checksums.
265 * 124 8/03/99 11:02p Dave
266 * Maybe fixed sync problems in multiplayer.
268 * 123 8/03/99 6:21p Jefff
271 * 122 8/03/99 3:44p Andsager
272 * Launch laucher if trying to run FS without first having configured
275 * 121 8/03/99 12:45p Dave
278 * 120 8/02/99 9:13p Dave
281 * 119 7/30/99 10:31p Dave
282 * Added comm menu to the configurable hud files.
284 * 118 7/30/99 5:17p Andsager
285 * first fs2demo checksums
287 * 117 7/29/99 3:09p Anoop
289 * 116 7/29/99 12:05a Dave
290 * Nebula speed optimizations.
292 * 115 7/27/99 8:59a Andsager
293 * Make major, minor version consistent for all builds. Only show major
294 * and minor for launcher update window.
296 * 114 7/26/99 5:50p Dave
297 * Revised ingame join. Better? We'll see....
299 * 113 7/26/99 5:27p Andsager
300 * Add training mission as builtin to demo build
302 * 112 7/24/99 1:54p Dave
303 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
306 * 111 7/22/99 4:00p Dave
307 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
309 * 110 7/21/99 8:10p Dave
310 * First run of supernova effect.
312 * 109 7/20/99 1:49p Dave
313 * Peter Drake build. Fixed some release build warnings.
315 * 108 7/19/99 2:26p Andsager
316 * set demo multiplayer missions
318 * 107 7/18/99 5:19p Dave
319 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
321 * 106 7/16/99 1:50p Dave
322 * 8 bit aabitmaps. yay.
324 * 105 7/15/99 3:07p Dave
325 * 32 bit detection support. Mouse coord commandline.
327 * 104 7/15/99 2:13p Dave
328 * Added 32 bit detection.
330 * 103 7/15/99 9:20a Andsager
331 * FS2_DEMO initial checkin
333 * 102 7/14/99 11:02a Dave
334 * Skill level default back to easy. Blech.
336 * 101 7/09/99 5:54p Dave
337 * Seperated cruiser types into individual types. Added tons of new
338 * briefing icons. Campaign screen.
340 * 100 7/08/99 4:43p Andsager
341 * New check for sparky_hi and print if not found.
343 * 99 7/08/99 10:53a Dave
344 * New multiplayer interpolation scheme. Not 100% done yet, but still
345 * better than the old way.
347 * 98 7/06/99 4:24p Dave
348 * Mid-level checkin. Starting on some potentially cool multiplayer
351 * 97 7/06/99 3:35p Andsager
352 * Allow movie to play before red alert mission.
354 * 96 7/03/99 5:50p Dave
355 * Make rotated bitmaps draw properly in padlock views.
357 * 95 7/02/99 9:55p Dave
358 * Player engine wash sound.
360 * 94 7/02/99 4:30p Dave
361 * Much more sophisticated lightning support.
363 * 93 6/29/99 7:52p Dave
364 * Put in exception handling in FS2.
366 * 92 6/22/99 9:37p Dave
367 * Put in pof spewing.
369 * 91 6/16/99 4:06p Dave
370 * New pilot info popup. Added new draw-bitmap-as-poly function.
372 * 90 6/15/99 1:56p Andsager
373 * For release builds, allow start up in high res only with
376 * 89 6/15/99 9:34a Dave
377 * Fixed key checking in single threaded version of the stamp notification
380 * 88 6/09/99 2:55p Andsager
381 * Allow multiple asteroid subtypes (of large, medium, small) and follow
384 * 87 6/08/99 1:14a Dave
385 * Multi colored hud test.
387 * 86 6/04/99 9:52a Dave
388 * Fixed some rendering problems.
390 * 85 6/03/99 10:15p Dave
391 * Put in temporary main hall screen.
393 * 84 6/02/99 6:18p Dave
394 * Fixed TNT lockup problems! Wheeeee!
396 * 83 6/01/99 3:52p Dave
397 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
398 * dead popup, pxo find player popup, pxo private room popup.
400 * 82 5/26/99 1:28p Jasenw
401 * changed coords for loading ani
403 * 81 5/26/99 11:46a Dave
404 * Added ship-blasting lighting and made the randomization of lighting
405 * much more customizable.
407 * 80 5/24/99 5:45p Dave
408 * Added detail levels to the nebula, with a decent speedup. Split nebula
409 * lightning into its own section.
422 #include "systemvars.h"
427 #include "starfield.h"
428 #include "lighting.h"
433 #include "fireballs.h"
437 #include "floating.h"
438 #include "gamesequence.h"
440 #include "optionsmenu.h"
441 #include "playermenu.h"
442 #include "trainingmenu.h"
443 #include "techmenu.h"
446 #include "hudmessage.h"
448 #include "missiongoals.h"
449 #include "missionparse.h"
454 #include "multiutil.h"
455 #include "multimsgs.h"
459 #include "freespace.h"
460 #include "managepilot.h"
462 #include "contexthelp.h"
465 #include "missionbrief.h"
466 #include "missiondebrief.h"
468 #include "missionshipchoice.h"
470 #include "hudconfig.h"
471 #include "controlsconfig.h"
472 #include "missionmessage.h"
473 #include "missiontraining.h"
475 #include "hudtarget.h"
479 #include "eventmusic.h"
480 #include "animplay.h"
481 #include "missionweaponchoice.h"
482 #include "missionlog.h"
483 #include "audiostr.h"
485 #include "missioncampaign.h"
487 #include "missionhotkey.h"
488 #include "objectsnd.h"
489 #include "cmeasure.h"
491 #include "linklist.h"
492 #include "shockwave.h"
493 #include "afterburner.h"
498 #include "stand_gui.h"
499 #include "pcxutils.h"
500 #include "hudtargetbox.h"
501 #include "multi_xfer.h"
502 #include "hudescort.h"
503 #include "multiutil.h"
506 #include "multiteamselect.h"
509 #include "readyroom.h"
510 #include "mainhallmenu.h"
511 #include "multilag.h"
513 #include "particle.h"
515 #include "multi_ingame.h"
516 #include "snazzyui.h"
517 #include "asteroid.h"
518 #include "popupdead.h"
519 #include "multi_voice.h"
520 #include "missioncmdbrief.h"
521 #include "redalert.h"
522 #include "gameplayhelp.h"
523 #include "multilag.h"
524 #include "staticrand.h"
525 #include "multi_pmsg.h"
526 #include "levelpaging.h"
527 #include "observer.h"
528 #include "multi_pause.h"
529 #include "multi_endgame.h"
530 #include "cutscenes.h"
531 #include "multi_respawn.h"
532 // #include "movie.h"
533 #include "multi_obj.h"
534 #include "multi_log.h"
536 #include "localize.h"
537 #include "osregistry.h"
538 #include "barracks.h"
539 #include "missionpause.h"
541 #include "alphacolors.h"
542 #include "objcollide.h"
545 #include "neblightning.h"
546 #include "shipcontrails.h"
549 #include "multi_dogfight.h"
550 #include "multi_rate.h"
551 #include "muzzleflash.h"
555 #include "mainhalltemp.h"
556 #include "exceptionhandler.h"
558 #include "supernova.h"
559 #include "hudshield.h"
561 // #include "names.h"
563 #include "missionloopbrief.h"
567 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
573 // 1.00.04 5/26/98 MWA -- going final (12 pm)
574 // 1.00.03 5/26/98 MWA -- going final (3 am)
575 // 1.00.02 5/25/98 MWA -- going final
576 // 1.00.01 5/25/98 MWA -- going final
577 // 0.90 5/21/98 MWA -- getting ready for final.
578 // 0.10 4/9/98. Set by MK.
580 // Demo version: (obsolete since DEMO codebase split from tree)
581 // 0.03 4/10/98 AL. Interplay rev
582 // 0.02 4/8/98 MK. Increased when this system was modified.
583 // 0.01 4/7/98? AL. First release to Interplay QA.
586 // 1.00 5/28/98 AL. First release to Interplay QA.
588 void game_level_init(int seed = -1);
589 void game_post_level_init();
590 void game_do_frame();
591 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
592 void game_reset_time();
593 void game_show_framerate(); // draws framerate in lower right corner
595 int Game_no_clear = 0;
597 int Pofview_running = 0;
598 int Nebedit_running = 0;
600 typedef struct big_expl_flash {
601 float max_flash_intensity; // max intensity
602 float cur_flash_intensity; // cur intensity
603 int flash_start; // start time
606 #define FRAME_FILTER 16
608 #define DEFAULT_SKILL_LEVEL 1
609 int Game_skill_level = DEFAULT_SKILL_LEVEL;
611 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
612 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
614 #define EXE_FNAME ("fs2.exe")
615 #define LAUNCHER_FNAME ("freespace2.exe")
617 // JAS: Code for warphole camera.
618 // Needs to be cleaned up.
619 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
620 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
621 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
622 matrix Camera_orient = IDENTITY_MATRIX;
623 float Camera_damping = 1.0f;
624 float Camera_time = 0.0f;
625 float Warpout_time = 0.0f;
626 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
627 int Warpout_sound = -1;
629 int Use_joy_mouse = 0;
630 int Use_palette_flash = 1;
632 int Use_fullscreen_at_startup = 0;
634 int Show_area_effect = 0;
635 object *Last_view_target = NULL;
637 int dogfight_blown = 0;
640 float frametimes[FRAME_FILTER];
641 float frametotal = 0.0f;
645 int Show_framerate = 0;
647 int Show_framerate = 1;
650 int Framerate_cap = 120;
653 int Show_target_debug_info = 0;
654 int Show_target_weapons = 0;
656 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
658 int Debug_octant = -1;
660 fix Game_time_compression = F1_0;
662 // if the ships.tbl the player has is valid
663 int Game_ships_tbl_valid = 0;
665 // if the weapons.tbl the player has is valid
666 int Game_weapons_tbl_valid = 0;
670 extern int Player_attacking_enabled;
674 int Pre_player_entry;
676 int Fred_running = 0;
677 char Game_current_mission_filename[MAX_FILENAME_LEN];
678 int game_single_step = 0;
679 int last_single_step=0;
681 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
682 extern int MSG_WINDOW_Y_START;
683 extern int MSG_WINDOW_HEIGHT;
685 int game_zbuffer = 1;
686 //static int Game_music_paused;
687 static int Game_paused;
691 #define EXPIRE_BAD_CHECKSUM 1
692 #define EXPIRE_BAD_TIME 2
694 extern void ssm_init();
695 extern void ssm_level_init();
696 extern void ssm_process();
698 // static variable to contain the time this version was built
699 // commented out for now until
700 // I figure out how to get the username into the file
701 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
703 // defines and variables used for dumping frame for making trailers.
705 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
706 int Debug_dump_trigger = 0;
707 int Debug_dump_frame_count;
708 int Debug_dump_frame_num = 0;
709 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
712 // amount of time to wait after the player has died before we display the death died popup
713 #define PLAYER_DIED_POPUP_WAIT 2500
714 int Player_died_popup_wait = -1;
715 int Player_multi_died_check = -1;
717 // builtin mission list stuff
719 int Game_builtin_mission_count = 6;
720 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
721 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
722 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
723 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
724 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
725 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
726 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
728 #elif defined(PD_BUILD)
729 int Game_builtin_mission_count = 4;
730 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
731 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
732 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
733 { "sm1-01", (FSB_FROM_VOLITION), "" },
734 { "sm1-05", (FSB_FROM_VOLITION), "" },
736 #elif defined(MULTIPLAYER_BETA)
737 int Game_builtin_mission_count = 17;
738 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
740 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
741 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
742 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
743 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
744 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
745 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
746 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
747 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
748 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
749 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
750 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
751 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
752 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
753 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
754 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
755 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
756 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
758 #elif defined(OEM_BUILD)
759 int Game_builtin_mission_count = 17;
760 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
761 // oem version - act 1 only
762 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
765 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
766 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
767 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
768 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
769 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
770 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
771 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
772 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
773 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
774 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
775 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
776 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
777 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
778 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
779 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
780 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
783 int Game_builtin_mission_count = 92;
784 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
785 // single player campaign
786 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
789 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
790 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
791 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
792 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
793 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
794 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
795 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
796 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
797 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
798 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
799 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
800 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
801 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
802 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
803 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
804 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
805 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
806 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
807 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
810 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
811 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
812 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
813 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
814 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
815 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
816 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
817 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
818 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
819 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
822 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
823 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
824 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
825 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
826 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
827 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
828 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
829 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
830 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
831 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
832 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
833 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
835 // multiplayer missions
838 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
844 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
845 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
846 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
849 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
852 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
855 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
858 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
859 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
861 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
862 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
864 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
865 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
892 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
893 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
894 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
895 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
900 // Internal function prototypes
901 void game_maybe_draw_mouse(float frametime);
902 void init_animating_pointer();
903 void load_animating_pointer(char *filename, int dx, int dy);
904 void unload_animating_pointer();
905 void game_do_training_checks();
906 void game_shutdown(void);
907 void game_show_event_debug(float frametime);
908 void game_event_debug_init();
910 void demo_upsell_show_screens();
911 void game_start_subspace_ambient_sound();
912 void game_stop_subspace_ambient_sound();
913 void verify_ships_tbl();
914 void verify_weapons_tbl();
915 void display_title_screen();
917 // loading background filenames
918 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
919 "LoadingBG", // GR_640
920 "2_LoadingBG" // GR_1024
924 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
925 "Loading.ani", // GR_640
926 "2_Loading.ani" // GR_1024
929 #if defined(FS2_DEMO)
930 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
934 #elif defined(OEM_BUILD)
935 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
942 char Game_CDROM_dir[MAX_PATH_LEN];
945 // How much RAM is on this machine. Set in WinMain
946 uint Freespace_total_ram = 0;
949 float Game_flash_red = 0.0f;
950 float Game_flash_green = 0.0f;
951 float Game_flash_blue = 0.0f;
952 float Sun_spot = 0.0f;
953 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
955 // game shudder stuff (in ms)
956 int Game_shudder_time = -1;
957 int Game_shudder_total = 0;
958 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
961 sound_env Game_sound_env;
962 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
963 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
965 int Game_sound_env_update_timestamp;
967 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
970 // WARPIN CRAP END --------------------------------------------------------------------------------------------
972 fs_builtin_mission *game_find_builtin_mission(char *filename)
976 // look through all existing builtin missions
977 for(idx=0; idx<Game_builtin_mission_count; idx++){
978 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
979 return &Game_builtin_mission_list[idx];
987 int game_get_default_skill_level()
989 return DEFAULT_SKILL_LEVEL;
993 void game_flash_reset()
995 Game_flash_red = 0.0f;
996 Game_flash_green = 0.0f;
997 Game_flash_blue = 0.0f;
999 Big_expl_flash.max_flash_intensity = 0.0f;
1000 Big_expl_flash.cur_flash_intensity = 0.0f;
1001 Big_expl_flash.flash_start = 0;
1004 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1005 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1007 void game_framerate_check_init()
1009 // zero critical time
1010 Gf_critical_time = 0.0f;
1013 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1014 // if this is a glide card
1015 if(gr_screen.mode == GR_GLIDE){
1016 extern GrHwConfiguration hwconfig;
1019 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1020 Gf_critical = 15.0f;
1024 Gf_critical = 10.0f;
1027 // d3d. only care about good cards here I guess (TNT)
1029 Gf_critical = 15.0f;
1032 // if this is a glide card
1033 if(gr_screen.mode == GR_GLIDE){
1034 extern GrHwConfiguration hwconfig;
1037 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1038 Gf_critical = 25.0f;
1042 Gf_critical = 20.0f;
1045 // d3d. only care about good cards here I guess (TNT)
1047 Gf_critical = 25.0f;
1052 extern float Framerate;
1053 void game_framerate_check()
1057 // if the current framerate is above the critical level, add frametime
1058 if(Framerate >= Gf_critical){
1059 Gf_critical_time += flFrametime;
1062 if(!Show_framerate){
1066 // display if we're above the critical framerate
1067 if(Framerate < Gf_critical){
1068 gr_set_color_fast(&Color_bright_red);
1069 gr_string(200, y_start, "Framerate warning");
1074 // display our current pct of good frametime
1075 if(f2fl(Missiontime) >= 0.0f){
1076 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1079 gr_set_color_fast(&Color_bright_green);
1081 gr_set_color_fast(&Color_bright_red);
1084 gr_printf(200, y_start, "%d%%", (int)pct);
1091 // Adds a flash effect. These can be positive or negative.
1092 // The range will get capped at around -1 to 1, so stick
1093 // with a range like that.
1094 void game_flash( float r, float g, float b )
1096 Game_flash_red += r;
1097 Game_flash_green += g;
1098 Game_flash_blue += b;
1100 if ( Game_flash_red < -1.0f ) {
1101 Game_flash_red = -1.0f;
1102 } else if ( Game_flash_red > 1.0f ) {
1103 Game_flash_red = 1.0f;
1106 if ( Game_flash_green < -1.0f ) {
1107 Game_flash_green = -1.0f;
1108 } else if ( Game_flash_green > 1.0f ) {
1109 Game_flash_green = 1.0f;
1112 if ( Game_flash_blue < -1.0f ) {
1113 Game_flash_blue = -1.0f;
1114 } else if ( Game_flash_blue > 1.0f ) {
1115 Game_flash_blue = 1.0f;
1120 // Adds a flash for Big Ship explosions
1121 // cap range from 0 to 1
1122 void big_explosion_flash(float flash)
1124 Big_expl_flash.flash_start = timestamp(1);
1128 } else if (flash < 0.0f) {
1132 Big_expl_flash.max_flash_intensity = flash;
1133 Big_expl_flash.cur_flash_intensity = 0.0f;
1136 // Amount to diminish palette towards normal, per second.
1137 #define DIMINISH_RATE 0.75f
1138 #define SUN_DIMINISH_RATE 6.00f
1142 float sn_glare_scale = 1.7f;
1145 dc_get_arg(ARG_FLOAT);
1146 sn_glare_scale = Dc_arg_float;
1149 float Supernova_last_glare = 0.0f;
1150 void game_sunspot_process(float frametime)
1154 float Sun_spot_goal = 0.0f;
1157 sn_stage = supernova_active();
1159 // sunspot differently based on supernova stage
1161 // approaching. player still in control
1164 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1167 light_get_global_dir(&light_dir, 0);
1169 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1172 // scale it some more
1173 dot = dot * (0.5f + (pct * 0.5f));
1176 Sun_spot_goal += (dot * sn_glare_scale);
1179 // draw the sun glow
1180 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1181 // draw the glow for this sun
1182 stars_draw_sun_glow(0);
1185 Supernova_last_glare = Sun_spot_goal;
1188 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1191 Sun_spot_goal = 0.9f;
1192 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1194 if(Sun_spot_goal > 1.0f){
1195 Sun_spot_goal = 1.0f;
1198 Sun_spot_goal *= sn_glare_scale;
1199 Supernova_last_glare = Sun_spot_goal;
1202 // fade to white. display dead popup
1205 Supernova_last_glare += (2.0f * flFrametime);
1206 if(Supernova_last_glare > 2.0f){
1207 Supernova_last_glare = 2.0f;
1210 Sun_spot_goal = Supernova_last_glare;
1217 // check sunspots for all suns
1218 n_lights = light_get_global_count();
1221 for(idx=0; idx<n_lights; idx++){
1222 //(vector *eye_pos, matrix *eye_orient)
1223 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1226 light_get_global_dir(&light_dir, idx);
1228 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1230 Sun_spot_goal += (float)pow(dot,85.0f);
1232 // draw the glow for this sun
1233 stars_draw_sun_glow(idx);
1235 Sun_spot_goal = 0.0f;
1241 Sun_spot_goal = 0.0f;
1245 float dec_amount = frametime*SUN_DIMINISH_RATE;
1247 if ( Sun_spot < Sun_spot_goal ) {
1248 Sun_spot += dec_amount;
1249 if ( Sun_spot > Sun_spot_goal ) {
1250 Sun_spot = Sun_spot_goal;
1252 } else if ( Sun_spot > Sun_spot_goal ) {
1253 Sun_spot -= dec_amount;
1254 if ( Sun_spot < Sun_spot_goal ) {
1255 Sun_spot = Sun_spot_goal;
1261 // Call once a frame to diminish the
1262 // flash effect to 0.
1263 void game_flash_diminish(float frametime)
1265 float dec_amount = frametime*DIMINISH_RATE;
1267 if ( Game_flash_red > 0.0f ) {
1268 Game_flash_red -= dec_amount;
1269 if ( Game_flash_red < 0.0f )
1270 Game_flash_red = 0.0f;
1272 Game_flash_red += dec_amount;
1273 if ( Game_flash_red > 0.0f )
1274 Game_flash_red = 0.0f;
1277 if ( Game_flash_green > 0.0f ) {
1278 Game_flash_green -= dec_amount;
1279 if ( Game_flash_green < 0.0f )
1280 Game_flash_green = 0.0f;
1282 Game_flash_green += dec_amount;
1283 if ( Game_flash_green > 0.0f )
1284 Game_flash_green = 0.0f;
1287 if ( Game_flash_blue > 0.0f ) {
1288 Game_flash_blue -= dec_amount;
1289 if ( Game_flash_blue < 0.0f )
1290 Game_flash_blue = 0.0f;
1292 Game_flash_blue += dec_amount;
1293 if ( Game_flash_blue > 0.0f )
1294 Game_flash_blue = 0.0f;
1297 // update big_explosion_cur_flash
1298 #define TIME_UP 1500
1299 #define TIME_DOWN 2500
1300 int duration = TIME_UP + TIME_DOWN;
1301 int time = timestamp_until(Big_expl_flash.flash_start);
1302 if (time > -duration) {
1304 if (time < TIME_UP) {
1305 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1308 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1312 if ( Use_palette_flash ) {
1314 static int or=0, og=0, ob=0;
1316 // Change the 200 to change the color range of colors.
1317 r = fl2i( Game_flash_red*128.0f );
1318 g = fl2i( Game_flash_green*128.0f );
1319 b = fl2i( Game_flash_blue*128.0f );
1321 if ( Sun_spot > 0.0f ) {
1322 r += fl2i(Sun_spot*128.0f);
1323 g += fl2i(Sun_spot*128.0f);
1324 b += fl2i(Sun_spot*128.0f);
1327 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1328 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1329 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1330 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1333 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1334 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1335 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1337 if ( (r!=0) || (g!=0) || (b!=0) ) {
1338 gr_flash( r, g, b );
1340 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1351 void game_level_close()
1353 // De-Initialize the game subsystems
1354 message_mission_shutdown();
1355 event_music_level_close();
1356 game_stop_looped_sounds();
1358 obj_snd_level_close(); // uninit object-linked persistant sounds
1359 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1360 anim_level_close(); // stop and clean up any anim instances
1361 shockwave_level_close();
1362 fireball_level_close();
1364 mission_event_shutdown();
1365 asteroid_level_close();
1366 model_cache_reset(); // Reset/free all the model caching stuff
1367 flak_level_close(); // unload flak stuff
1368 neb2_level_close(); // shutdown gaseous nebula stuff
1371 mflash_level_close();
1373 audiostream_unpause_all();
1378 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1379 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1380 void game_level_init(int seed)
1382 // seed the random number generator
1384 // if no seed was passed, seed the generator either from the time value, or from the
1385 // netgame security flags -- ensures that all players in multiplayer game will have the
1386 // same randon number sequence (with static rand functions)
1387 if ( Game_mode & GM_NORMAL ) {
1388 Game_level_seed = time(NULL);
1390 Game_level_seed = Netgame.security;
1393 // mwa 9/17/98 -- maybe this assert isn't needed????
1394 Assert( !(Game_mode & GM_MULTIPLAYER) );
1395 Game_level_seed = seed;
1397 srand( Game_level_seed );
1399 // semirand function needs to get re-initted every time in multiplayer
1400 if ( Game_mode & GM_MULTIPLAYER ){
1406 Key_normal_game = (Game_mode & GM_NORMAL);
1409 Game_shudder_time = -1;
1411 // Initialize the game subsystems
1412 // timestamp_reset(); // Must be inited before everything else
1414 game_reset_time(); // resets time, and resets saved time too
1416 obj_init(); // Must be inited before the other systems
1417 model_free_all(); // Free all existing models
1418 mission_brief_common_init(); // Free all existing briefing/debriefing text
1419 weapon_level_init();
1420 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1422 player_level_init();
1423 shipfx_flash_init(); // Init the ship gun flash system.
1424 game_flash_reset(); // Reset the flash effect
1425 particle_init(); // Reset the particle system
1429 shield_hit_init(); // Initialize system for showing shield hits
1430 radar_mission_init();
1431 mission_init_goals();
1434 obj_snd_level_init(); // init object-linked persistant sounds
1436 shockwave_level_init();
1437 afterburner_level_init();
1438 scoring_level_init( &Player->stats );
1440 asteroid_level_init();
1441 control_config_clear_used_status();
1442 collide_ship_ship_sounds_init();
1444 Pre_player_entry = 1; // Means the player has not yet entered.
1445 Entry_delay_time = 0; // Could get overwritten in mission read.
1446 fireball_preload(); // page in warphole bitmaps
1448 flak_level_init(); // initialize flak - bitmaps, etc
1449 ct_level_init(); // initialize ships contrails, etc
1450 awacs_level_init(); // initialize AWACS
1451 beam_level_init(); // initialize beam weapons
1452 mflash_level_init();
1454 supernova_level_init();
1456 // multiplayer dogfight hack
1459 shipfx_engine_wash_level_init();
1463 Last_view_target = NULL;
1468 // campaign wasn't ended
1469 Campaign_ended_in_mission = 0;
1472 // called when a mission is over -- does server specific stuff.
1473 void freespace_stop_mission()
1476 Game_mode &= ~GM_IN_MISSION;
1479 // called at frame interval to process networking stuff
1480 void game_do_networking()
1482 Assert( Net_player != NULL );
1483 if (!(Game_mode & GM_MULTIPLAYER)){
1487 // see if this player should be reading/writing data. Bit is set when at join
1488 // screen onward until quits back to main menu.
1489 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1493 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1496 multi_pause_do_frame();
1501 // Loads the best palette for this level, based
1502 // on nebula color and hud color. You could just call palette_load_table with
1503 // the appropriate filename, but who wants to do that.
1504 void game_load_palette()
1506 char palette_filename[1024];
1508 // We only use 3 hud colors right now
1509 // Assert( HUD_config.color >= 0 );
1510 // Assert( HUD_config.color <= 2 );
1512 Assert( Mission_palette >= 0 );
1513 Assert( Mission_palette <= 98 );
1515 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1516 strcpy( palette_filename, NOX("gamepalette-subspace") );
1518 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1521 mprintf(( "Loading palette %s\n", palette_filename ));
1523 // palette_load_table(palette_filename);
1526 void game_post_level_init()
1528 // Stuff which gets called after mission is loaded. Because player isn't created until
1529 // after mission loads, some things must get initted after the level loads
1531 model_level_post_init();
1534 hud_setup_escort_list();
1535 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1541 game_event_debug_init();
1544 training_mission_init();
1545 asteroid_create_all();
1547 game_framerate_check_init();
1551 // An estimate as to how high the count passed to game_loading_callback will go.
1552 // This is just a guess, it seems to always be about the same. The count is
1553 // proportional to the code being executed, not the time, so this works good
1554 // for a bar, assuming the code does about the same thing each time you
1555 // load a level. You can find this value by looking at the return value
1556 // of game_busy_callback(NULL), which I conveniently print out to the
1557 // debug output window with the '=== ENDING LOAD ==' stuff.
1558 //#define COUNT_ESTIMATE 3706
1559 #define COUNT_ESTIMATE 1111
1561 int Game_loading_callback_inited = 0;
1563 int Game_loading_background = -1;
1564 anim * Game_loading_ani = NULL;
1565 anim_instance *Game_loading_ani_instance;
1566 int Game_loading_frame=-1;
1568 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1577 // This gets called 10x per second and count is the number of times
1578 // game_busy() has been called since the current callback function
1580 void game_loading_callback(int count)
1582 game_do_networking();
1584 Assert( Game_loading_callback_inited==1 );
1585 Assert( Game_loading_ani != NULL );
1587 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1588 if ( framenum > Game_loading_ani->total_frames-1 ) {
1589 framenum = Game_loading_ani->total_frames-1;
1590 } else if ( framenum < 0 ) {
1595 while ( Game_loading_frame < framenum ) {
1596 Game_loading_frame++;
1597 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1601 if ( cbitmap > -1 ) {
1602 if ( Game_loading_background > -1 ) {
1603 gr_set_bitmap( Game_loading_background );
1607 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1608 gr_set_bitmap( cbitmap );
1609 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1611 bm_release(cbitmap);
1617 void game_loading_callback_init()
1619 Assert( Game_loading_callback_inited==0 );
1621 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1622 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1625 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1626 Assert( Game_loading_ani != NULL );
1627 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1628 Assert( Game_loading_ani_instance != NULL );
1629 Game_loading_frame = -1;
1631 Game_loading_callback_inited = 1;
1633 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1638 void game_loading_callback_close()
1640 Assert( Game_loading_callback_inited==1 );
1642 // Make sure bar shows all the way over.
1643 game_loading_callback(COUNT_ESTIMATE);
1645 int real_count = game_busy_callback( NULL );
1648 Game_loading_callback_inited = 0;
1651 mprintf(( "=================== ENDING LOAD ================\n" ));
1652 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1653 mprintf(( "================================================\n" ));
1655 // to remove warnings in release build
1659 free_anim_instance(Game_loading_ani_instance);
1660 Game_loading_ani_instance = NULL;
1661 anim_free(Game_loading_ani);
1662 Game_loading_ani = NULL;
1664 bm_release( Game_loading_background );
1665 common_free_interface_palette(); // restore game palette
1666 Game_loading_background = -1;
1668 gr_set_font( FONT1 );
1671 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1673 void game_maybe_update_sound_environment()
1675 // do nothing for now
1678 // Assign the sound environment for the game, based on the current mission
1680 void game_assign_sound_environment()
1683 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1684 Game_sound_env.id = SND_ENV_DRUGGED;
1685 Game_sound_env.volume = 0.800f;
1686 Game_sound_env.damping = 1.188f;
1687 Game_sound_env.decay = 6.392f;
1689 } else if (Num_asteroids > 30) {
1690 Game_sound_env.id = SND_ENV_AUDITORIUM;
1691 Game_sound_env.volume = 0.603f;
1692 Game_sound_env.damping = 0.5f;
1693 Game_sound_env.decay = 4.279f;
1696 Game_sound_env = Game_default_sound_env;
1700 Game_sound_env = Game_default_sound_env;
1701 Game_sound_env_update_timestamp = timestamp(1);
1704 // function which gets called before actually entering the mission. It is broken down into a funciton
1705 // since it will get called in one place from a single player game and from another place for
1706 // a multiplayer game
1707 void freespace_mission_load_stuff()
1709 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1710 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1711 if(!(Game_mode & GM_STANDALONE_SERVER)){
1713 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1715 game_loading_callback_init();
1717 event_music_level_init(); // preloads the first 2 seconds for each event music track
1720 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1723 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1726 ship_assign_sound_all(); // assign engine sounds to ships
1727 game_assign_sound_environment(); // assign the sound environment for this mission
1730 // call function in missionparse.cpp to fixup player/ai stuff.
1731 mission_parse_fixup_players();
1734 // Load in all the bitmaps for this level
1739 game_loading_callback_close();
1741 // the only thing we need to call on the standalone for now.
1743 // call function in missionparse.cpp to fixup player/ai stuff.
1744 mission_parse_fixup_players();
1746 // Load in all the bitmaps for this level
1752 uint load_mission_load;
1753 uint load_post_level_init;
1754 uint load_mission_stuff;
1756 // tells the server to load the mission and initialize structures
1757 int game_start_mission()
1759 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1761 load_gl_init = time(NULL);
1763 load_gl_init = time(NULL) - load_gl_init;
1765 if (Game_mode & GM_MULTIPLAYER) {
1766 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1768 // clear multiplayer stats
1769 init_multiplayer_stats();
1772 load_mission_load = time(NULL);
1773 if (mission_load()) {
1774 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1775 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1776 gameseq_post_event(GS_EVENT_MAIN_MENU);
1778 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1783 load_mission_load = time(NULL) - load_mission_load;
1785 // If this is a red alert mission in campaign mode, bash wingman status
1786 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1787 red_alert_bash_wingman_status();
1790 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1791 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1792 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1793 // game_load_palette();
1796 load_post_level_init = time(NULL);
1797 game_post_level_init();
1798 load_post_level_init = time(NULL) - load_post_level_init;
1802 void Do_model_timings_test();
1803 Do_model_timings_test();
1807 load_mission_stuff = time(NULL);
1808 freespace_mission_load_stuff();
1809 load_mission_stuff = time(NULL) - load_mission_stuff;
1814 int Interface_framerate = 0;
1817 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1818 DCF_BOOL( show_framerate, Show_framerate )
1819 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1820 DCF_BOOL( show_target_weapons, Show_target_weapons )
1821 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1822 DCF_BOOL( sound, Sound_enabled )
1823 DCF_BOOL( zbuffer, game_zbuffer )
1824 DCF_BOOL( shield_system, New_shield_system )
1825 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1826 DCF_BOOL( player_attacking, Player_attacking_enabled )
1827 DCF_BOOL( show_waypoints, Show_waypoints )
1828 DCF_BOOL( show_area_effect, Show_area_effect )
1829 DCF_BOOL( show_net_stats, Show_net_stats )
1830 DCF_BOOL( log, Log_debug_output_to_file )
1831 DCF_BOOL( training_msg_method, Training_msg_method )
1832 DCF_BOOL( show_player_pos, Show_player_pos )
1833 DCF_BOOL(i_framerate, Interface_framerate )
1835 DCF(show_mem,"Toggles showing mem usage")
1838 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1839 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1840 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1841 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1847 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1849 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1850 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1854 DCF(show_cpu,"Toggles showing cpu usage")
1857 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1858 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1859 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1860 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1866 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1868 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1869 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1876 // AL 4-8-98: always allow players to display their framerate
1879 DCF_BOOL( show_framerate, Show_framerate )
1886 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1889 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1890 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1891 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1892 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1894 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" );
1895 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1897 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1900 DCF(palette_flash,"Toggles palette flash effect on/off")
1903 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1904 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1905 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1906 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1908 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1909 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1912 int Use_low_mem = 0;
1914 DCF(low_mem,"Uses low memory settings regardless of RAM")
1917 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1918 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1919 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1920 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1922 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1923 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1925 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1931 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1934 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1935 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1936 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1937 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1939 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1940 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1941 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1945 int Framerate_delay = 0;
1947 float Freespace_gamma = 1.0f;
1949 DCF(gamma,"Sets Gamma factor")
1952 dc_get_arg(ARG_FLOAT|ARG_NONE);
1953 if ( Dc_arg_type & ARG_FLOAT ) {
1954 Freespace_gamma = Dc_arg_float;
1956 dc_printf( "Gamma reset to 1.0f\n" );
1957 Freespace_gamma = 1.0f;
1959 if ( Freespace_gamma < 0.1f ) {
1960 Freespace_gamma = 0.1f;
1961 } else if ( Freespace_gamma > 5.0f ) {
1962 Freespace_gamma = 5.0f;
1964 gr_set_gamma(Freespace_gamma);
1966 char tmp_gamma_string[32];
1967 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1968 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1972 dc_printf( "Usage: gamma <float>\n" );
1973 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
1974 Dc_status = 0; // don't print status if help is printed. Too messy.
1978 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
1987 Game_current_mission_filename[0] = 0;
1989 // seed the random number generator
1990 Game_init_seed = time(NULL);
1991 srand( Game_init_seed );
1993 Framerate_delay = 0;
1999 extern void bm_init();
2005 // Initialize the timer before the os
2012 GetCurrentDirectory(1024, whee);
2014 strcat(whee, EXE_FNAME);
2016 //Initialize the libraries
2017 s1 = timer_get_milliseconds();
2018 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2021 e1 = timer_get_milliseconds();
2023 // time a bunch of cfopens
2025 s2 = timer_get_milliseconds();
2027 for(int idx=0; idx<10000; idx++){
2028 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2033 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2035 e2 = timer_get_milliseconds();
2038 if (Is_standalone) {
2039 std_init_standalone();
2041 os_init( Osreg_class_name, Osreg_app_name );
2042 os_set_title(Osreg_title);
2045 // initialize localization module. Make sure this is down AFTER initialzing OS.
2046 // int t1 = timer_get_milliseconds();
2049 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2051 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2054 // verify that he has a valid weapons.tbl
2055 verify_weapons_tbl();
2057 // Output version numbers to registry for auto patching purposes
2058 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2059 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2060 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2062 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2063 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2064 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2067 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2071 Asteroids_enabled = 1;
2074 /////////////////////////////
2076 /////////////////////////////
2081 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2082 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2084 if (!stricmp(ptr, NOX("no sound"))) {
2085 Cmdline_freespace_no_sound = 1;
2087 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2089 } else if (!stricmp(ptr, NOX("EAX"))) {
2094 if (!Is_standalone) {
2095 snd_init(use_a3d, use_eax);
2097 /////////////////////////////
2099 /////////////////////////////
2101 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2103 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);
2105 // fire up the UpdateLauncher executable
2107 PROCESS_INFORMATION pi;
2109 memset( &si, 0, sizeof(STARTUPINFO) );
2112 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2113 NULL, // pointer to command line string
2114 NULL, // pointer to process security attributes
2115 NULL, // pointer to thread security attributes
2116 FALSE, // handle inheritance flag
2117 CREATE_DEFAULT_ERROR_MODE, // creation flags
2118 NULL, // pointer to new environment block
2119 NULL, // pointer to current directory name
2120 &si, // pointer to STARTUPINFO
2121 &pi // pointer to PROCESS_INFORMATION
2124 // If the Launcher could not be started up, let the user know
2126 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2133 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2134 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);
2139 // check for hi res pack file
2140 int has_sparky_hi = 0;
2142 // check if sparky_hi exists -- access mode 0 means does file exist
2145 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2148 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2151 // see if we've got 32 bit in the string
2152 if(strstr(ptr, "32 bit")){
2158 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2160 // always 640 for E3
2161 gr_init(GR_640, GR_GLIDE);
2163 // regular or hi-res ?
2165 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2167 if(strstr(ptr, NOX("(1024x768)"))){
2169 gr_init(GR_1024, GR_GLIDE);
2171 gr_init(GR_640, GR_GLIDE);
2174 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2176 // always 640 for E3
2178 gr_init(GR_640, GR_DIRECT3D, depth);
2180 // regular or hi-res ?
2182 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2184 if(strstr(ptr, NOX("(1024x768)"))){
2188 gr_init(GR_1024, GR_DIRECT3D, depth);
2192 gr_init(GR_640, GR_DIRECT3D, depth);
2198 if ( Use_fullscreen_at_startup && !Is_standalone) {
2199 gr_init(GR_640, GR_DIRECTDRAW);
2201 gr_init(GR_640, GR_SOFTWARE);
2204 if ( !Is_standalone ) {
2205 gr_init(GR_640, GR_DIRECTDRAW);
2207 gr_init(GR_640, GR_SOFTWARE);
2213 extern int Gr_inited;
2214 if(trying_d3d && !Gr_inited){
2215 extern char Device_init_error[512];
2216 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2222 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2223 Freespace_gamma = (float)atof(ptr);
2224 if ( Freespace_gamma < 0.1f ) {
2225 Freespace_gamma = 0.1f;
2226 } else if ( Freespace_gamma > 5.0f ) {
2227 Freespace_gamma = 5.0f;
2229 char tmp_gamma_string[32];
2230 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2231 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2233 gr_set_gamma(Freespace_gamma);
2235 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2238 display_title_screen();
2242 // attempt to load up master tracker registry info (login and password)
2243 Multi_tracker_id = -1;
2245 // pxo login and password
2246 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2248 nprintf(("Network","Error reading in PXO login data\n"));
2249 strcpy(Multi_tracker_login,"");
2251 strcpy(Multi_tracker_login,ptr);
2253 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2255 nprintf(("Network","Error reading PXO password\n"));
2256 strcpy(Multi_tracker_passwd,"");
2258 strcpy(Multi_tracker_passwd,ptr);
2261 // pxo squad name and password
2262 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2264 nprintf(("Network","Error reading in PXO squad name\n"));
2265 strcpy(Multi_tracker_squad_name, "");
2267 strcpy(Multi_tracker_squad_name, ptr);
2270 // If less than 48MB of RAM, use low memory model.
2271 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2272 mprintf(( "Using normal memory settings...\n" ));
2273 bm_set_low_mem(1); // Use every other frame of bitmaps
2275 mprintf(( "Using high memory settings...\n" ));
2276 bm_set_low_mem(0); // Use all frames of bitmaps
2279 // load non-darkening pixel defs
2280 palman_load_pixels();
2282 // hud shield icon stuff
2283 hud_shield_game_init();
2285 control_config_common_init(); // sets up localization stuff in the control config
2291 gamesnd_parse_soundstbl();
2296 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2301 player_controls_init();
2304 //if(!Is_standalone){
2312 ship_init(); // read in ships.tbl
2314 mission_campaign_init(); // load in the default campaign
2316 // navmap_init(); // init the navigation map system
2317 context_help_init();
2318 techroom_intel_init(); // parse species.tbl, load intel info
2320 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2321 init_animating_pointer();
2323 mission_brief_common_init(); // Mark all the briefing structures as empty.
2324 gr_font_init(); // loads up all fonts
2326 neb2_init(); // fullneb stuff
2330 player_tips_init(); // helpful tips
2333 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2334 pilot_load_pic_list();
2335 pilot_load_squad_pic_list();
2337 load_animating_pointer(NOX("cursor"), 0, 0);
2339 // initialize alpha colors
2340 alpha_colors_init();
2343 // Game_music_paused = 0;
2348 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2349 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2351 mprintf(("cfile_init() took %d\n", e1 - s1));
2352 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2355 char transfer_text[128];
2357 float Start_time = 0.0f;
2359 float Framerate = 0.0f;
2361 float Timing_total = 0.0f;
2362 float Timing_render2 = 0.0f;
2363 float Timing_render3 = 0.0f;
2364 float Timing_flip = 0.0f;
2365 float Timing_clear = 0.0f;
2367 MONITOR(NumPolysDrawn);
2373 void game_get_framerate()
2375 char text[128] = "";
2377 if ( frame_int == -1 ) {
2379 for (i=0; i<FRAME_FILTER; i++ ) {
2380 frametimes[i] = 0.0f;
2385 frametotal -= frametimes[frame_int];
2386 frametotal += flFrametime;
2387 frametimes[frame_int] = flFrametime;
2388 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2390 if ( frametotal != 0.0 ) {
2391 if ( Framecount >= FRAME_FILTER )
2392 Framerate = FRAME_FILTER / frametotal;
2394 Framerate = Framecount / frametotal;
2395 sprintf( text, NOX("FPS: %.1f"), Framerate );
2397 sprintf( text, NOX("FPS: ?") );
2401 if (Show_framerate) {
2402 gr_set_color_fast(&HUD_color_debug);
2403 gr_string( 570, 2, text );
2407 void game_show_framerate()
2411 cur_time = f2fl(timer_get_approx_seconds());
2412 if (cur_time - Start_time > 30.0f) {
2413 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2414 Start_time += 1000.0f;
2417 //mprintf(( "%s\n", text ));
2420 if ( Debug_dump_frames )
2424 // possibly show control checking info
2425 control_check_indicate();
2427 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2428 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2429 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2430 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2433 if ( Show_cpu == 1 ) {
2438 dy = gr_get_font_height() + 1;
2440 gr_set_color_fast(&HUD_color_debug);
2443 extern int D3D_textures_in;
2444 extern int D3D_textures_in_frame;
2445 extern int Glide_textures_in;
2446 extern int Glide_textures_in_frame;
2447 extern int Glide_explosion_vram;
2448 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2450 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2452 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2455 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2457 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2459 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2461 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2463 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2468 extern int Num_pairs; // Number of object pairs that were checked.
2469 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2472 extern int Num_pairs_checked; // What percent of object pairs were checked.
2473 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2475 Num_pairs_checked = 0;
2479 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2482 if ( Timing_total > 0.01f ) {
2483 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2485 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2487 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2489 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2491 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2501 dy = gr_get_font_height() + 1;
2503 gr_set_color_fast(&HUD_color_debug);
2506 extern int TotalRam;
2507 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2512 extern int Model_ram;
2513 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2517 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2519 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2521 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2524 extern int D3D_textures_in;
2525 extern int Glide_textures_in;
2526 extern int Glide_textures_in_frame;
2527 extern int Glide_explosion_vram;
2528 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2530 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2532 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2538 if ( Show_player_pos ) {
2542 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));
2545 MONITOR_INC(NumPolys, modelstats_num_polys);
2546 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2547 MONITOR_INC(NumVerts, modelstats_num_verts );
2549 modelstats_num_polys = 0;
2550 modelstats_num_polys_drawn = 0;
2551 modelstats_num_verts = 0;
2552 modelstats_num_sortnorms = 0;
2556 void game_show_standalone_framerate()
2558 float frame_rate=30.0f;
2559 if ( frame_int == -1 ) {
2561 for (i=0; i<FRAME_FILTER; i++ ) {
2562 frametimes[i] = 0.0f;
2567 frametotal -= frametimes[frame_int];
2568 frametotal += flFrametime;
2569 frametimes[frame_int] = flFrametime;
2570 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2572 if ( frametotal != 0.0 ) {
2573 if ( Framecount >= FRAME_FILTER ){
2574 frame_rate = FRAME_FILTER / frametotal;
2576 frame_rate = Framecount / frametotal;
2579 std_set_standalone_fps(frame_rate);
2583 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2584 void game_show_time_left()
2588 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2589 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2590 // checking how much time is left
2592 if ( Mission_end_time == -1 ){
2596 diff = f2i(Mission_end_time - Missiontime);
2597 // be sure to bash to 0. diff could be negative on frame that we quit mission
2602 hud_set_default_color();
2603 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2606 //========================================================================================
2607 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2608 //========================================================================================
2612 DCF(ai_pause,"Pauses ai")
2615 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2616 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2617 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2618 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2621 obj_init_all_ships_physics();
2624 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2625 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2628 DCF(single_step,"Single steps the game")
2631 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2632 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2633 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2634 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2636 last_single_step = 0; // Make so single step waits a frame before stepping
2639 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2640 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2643 DCF_BOOL(physics_pause, physics_paused)
2644 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2645 DCF_BOOL(ai_firing, Ai_firing_enabled )
2647 // Create some simple aliases to these commands...
2648 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2649 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2650 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2651 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2652 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2655 //========================================================================================
2656 //========================================================================================
2659 void game_training_pause_do()
2663 key = game_check_key();
2665 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2672 void game_increase_skill_level()
2675 if (Game_skill_level >= NUM_SKILL_LEVELS){
2676 Game_skill_level = 0;
2680 int Player_died_time;
2682 int View_percent = 100;
2685 DCF(view, "Sets the percent of the 3d view to render.")
2688 dc_get_arg(ARG_INT);
2689 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2690 View_percent = Dc_arg_int;
2692 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2698 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2702 dc_printf("View is set to %d%%\n", View_percent );
2707 // Set the clip region for the 3d rendering window
2708 void game_set_view_clip()
2710 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2711 // Set the clip region for the letterbox "dead view"
2712 int yborder = gr_screen.max_h/4;
2714 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2715 // J.S. I've changed my ways!! See the new "no constants" code!!!
2716 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2718 // Set the clip region for normal view
2719 if ( View_percent >= 100 ) {
2722 int xborder, yborder;
2724 if ( View_percent < 5 ) {
2728 float fp = i2fl(View_percent)/100.0f;
2729 int fi = fl2i(fl_sqrt(fp)*100.0f);
2730 if ( fi > 100 ) fi=100;
2732 xborder = ( gr_screen.max_w*(100-fi) )/200;
2733 yborder = ( gr_screen.max_h*(100-fi) )/200;
2735 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2741 void show_debug_stuff()
2744 int laser_count = 0, missile_count = 0;
2746 for (i=0; i<MAX_OBJECTS; i++) {
2747 if (Objects[i].type == OBJ_WEAPON){
2748 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2750 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2756 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2759 extern int Tool_enabled;
2764 int tst_bitmap = -1;
2766 float tst_offset, tst_offset_total;
2769 void game_tst_frame_pre()
2777 g3_rotate_vertex(&v, &tst_pos);
2778 g3_project_vertex(&v);
2781 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2785 // big ship? always tst
2787 // within 3000 meters
2788 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2792 // within 300 meters
2793 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2800 void game_tst_frame()
2810 tst_time = time(NULL);
2812 // load the tst bitmap
2813 switch((int)frand_range(0.0f, 3.0)){
2815 tst_bitmap = bm_load("ig_jim");
2817 mprintf(("TST 0\n"));
2821 tst_bitmap = bm_load("ig_kan");
2823 mprintf(("TST 1\n"));
2827 tst_bitmap = bm_load("ig_jim");
2829 mprintf(("TST 2\n"));
2833 tst_bitmap = bm_load("ig_kan");
2835 mprintf(("TST 3\n"));
2844 // get the tst bitmap dimensions
2846 bm_get_info(tst_bitmap, &w, &h);
2849 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2851 snd_play(&Snds[SND_VASUDAN_BUP]);
2853 // tst x and direction
2857 tst_offset_total = (float)w;
2858 tst_offset = (float)w;
2860 tst_x = (float)gr_screen.max_w;
2861 tst_offset_total = (float)-w;
2862 tst_offset = (float)w;
2870 float diff = (tst_offset_total / 0.5f) * flFrametime;
2876 tst_offset -= fl_abs(diff);
2877 } else if(tst_mode == 2){
2880 tst_offset -= fl_abs(diff);
2884 gr_set_bitmap(tst_bitmap);
2885 gr_bitmap((int)tst_x, (int)tst_y);
2888 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2892 // if we passed the switch point
2893 if(tst_offset <= 0.0f){
2898 tst_stamp = timestamp(1000);
2899 tst_offset = fl_abs(tst_offset_total);
2910 void game_tst_mark(object *objp, ship *shipp)
2919 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2922 sip = &Ship_info[shipp->ship_info_index];
2929 tst_pos = objp->pos;
2930 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2936 extern void render_shields();
2938 void player_repair_frame(float frametime)
2940 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2942 for(idx=0;idx<MAX_PLAYERS;idx++){
2945 np = &Net_players[idx];
2947 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)){
2949 // don't rearm/repair if the player is dead or dying/departing
2950 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
2951 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
2956 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
2957 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
2963 #define NUM_FRAMES_TEST 300
2964 #define NUM_MIXED_SOUNDS 16
2965 void do_timing_test(float flFrametime)
2967 static int framecount = 0;
2968 static int test_running = 0;
2969 static float test_time = 0.0f;
2971 static int snds[NUM_MIXED_SOUNDS];
2974 if ( test_running ) {
2976 test_time += flFrametime;
2977 if ( framecount >= NUM_FRAMES_TEST ) {
2979 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
2980 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2985 if ( Test_begin == 1 ) {
2991 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2994 // start looping digital sounds
2995 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2996 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3003 DCF(dcf_fov, "Change the field of view")
3006 dc_get_arg(ARG_FLOAT|ARG_NONE);
3007 if ( Dc_arg_type & ARG_NONE ) {
3008 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3009 dc_printf( "Zoom factor reset\n" );
3011 if ( Dc_arg_type & ARG_FLOAT ) {
3012 if (Dc_arg_float < 0.25f) {
3013 Viewer_zoom = 0.25f;
3014 dc_printf("Zoom factor pinned at 0.25.\n");
3015 } else if (Dc_arg_float > 1.25f) {
3016 Viewer_zoom = 1.25f;
3017 dc_printf("Zoom factor pinned at 1.25.\n");
3019 Viewer_zoom = Dc_arg_float;
3025 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3028 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3032 DCF(framerate_cap, "Sets the framerate cap")
3035 dc_get_arg(ARG_INT);
3036 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3037 Framerate_cap = Dc_arg_int;
3039 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3045 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3046 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3047 dc_printf("[n] must be from 1 to 120.\n");
3051 if ( Framerate_cap )
3052 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3054 dc_printf("There is no framerate cap currently active.\n");
3058 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3059 int Show_viewing_from_self = 0;
3061 void say_view_target()
3063 object *view_target;
3065 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3066 view_target = &Objects[Player_ai->target_objnum];
3068 view_target = Player_obj;
3070 if (Game_mode & GM_DEAD) {
3071 if (Player_ai->target_objnum != -1)
3072 view_target = &Objects[Player_ai->target_objnum];
3075 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3076 if (view_target != Player_obj){
3078 char *view_target_name = NULL;
3079 switch(Objects[Player_ai->target_objnum].type) {
3081 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3084 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3085 Viewer_mode &= ~VM_OTHER_SHIP;
3087 case OBJ_JUMP_NODE: {
3088 char jump_node_name[128];
3089 strcpy(jump_node_name, XSTR( "jump node", 184));
3090 view_target_name = jump_node_name;
3091 Viewer_mode &= ~VM_OTHER_SHIP;
3100 if ( view_target_name ) {
3101 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3102 Show_viewing_from_self = 1;
3105 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3106 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3107 Show_viewing_from_self = 1;
3109 if (Show_viewing_from_self)
3110 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3115 Last_view_target = view_target;
3119 float Game_hit_x = 0.0f;
3120 float Game_hit_y = 0.0f;
3122 // Reset at the beginning of each frame
3123 void game_whack_reset()
3129 // Apply a 2d whack to the player
3130 void game_whack_apply( float x, float y )
3132 // Do some force feedback
3133 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3139 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3142 // call to apply a "shudder"
3143 void game_shudder_apply(int time, float intensity)
3145 Game_shudder_time = timestamp(time);
3146 Game_shudder_total = time;
3147 Game_shudder_intensity = intensity;
3150 #define FF_SCALE 10000
3151 void apply_hud_shake(matrix *eye_orient)
3153 if (Viewer_obj == Player_obj) {
3154 physics_info *pi = &Player_obj->phys_info;
3162 // Make eye shake due to afterburner
3163 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3166 dtime = timestamp_until(pi->afterburner_decay);
3170 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3171 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3174 // Make eye shake due to engine wash
3176 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3179 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3180 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3182 // get the intensity
3183 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3187 vm_vec_rand_vec_quick(&rand_vec);
3190 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3194 // make hud shake due to shuddering
3195 if(Game_shudder_time != -1){
3196 // if the timestamp has elapsed
3197 if(timestamp_elapsed(Game_shudder_time)){
3198 Game_shudder_time = -1;
3200 // otherwise apply some shudder
3204 dtime = timestamp_until(Game_shudder_time);
3208 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));
3209 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));
3214 vm_angles_2_matrix(&tm, &tangles);
3215 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3216 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3217 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3218 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3223 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3225 // Player's velocity just before he blew up. Used to keep camera target moving.
3226 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3228 // Set eye_pos and eye_orient based on view mode.
3229 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3233 static int last_Viewer_mode = 0;
3234 static int last_Game_mode = 0;
3235 static int last_Viewer_objnum = -1;
3237 // This code is supposed to detect camera "cuts"... like going between
3240 // determine if we need to regenerate the nebula
3241 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3242 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3243 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3244 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3245 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3246 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3247 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3248 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3249 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3252 // regenerate the nebula
3256 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3257 //mprintf(( "************** Camera cut! ************\n" ));
3258 last_Viewer_mode = Viewer_mode;
3259 last_Game_mode = Game_mode;
3261 // Camera moved. Tell stars & debris to not do blurring.
3267 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3268 player_display_packlock_view();
3271 game_set_view_clip();
3273 if (Game_mode & GM_DEAD) {
3274 vector vec_to_deader, view_pos;
3277 Viewer_mode |= VM_DEAD_VIEW;
3279 if (Player_ai->target_objnum != -1) {
3280 int view_from_player = 1;
3282 if (Viewer_mode & VM_OTHER_SHIP) {
3283 // View from target.
3284 Viewer_obj = &Objects[Player_ai->target_objnum];
3286 last_Viewer_objnum = Player_ai->target_objnum;
3288 if ( Viewer_obj->type == OBJ_SHIP ) {
3289 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3290 view_from_player = 0;
3293 last_Viewer_objnum = -1;
3296 if ( view_from_player ) {
3297 // View target from player ship.
3299 *eye_pos = Player_obj->pos;
3300 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3301 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3304 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3306 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3307 dist += flFrametime * 16.0f;
3309 vm_vec_scale(&vec_to_deader, -dist);
3310 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3312 view_pos = Player_obj->pos;
3314 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3315 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3316 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3317 Dead_player_last_vel = Player_obj->phys_info.vel;
3318 //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));
3319 } else if (Player_ai->target_objnum != -1) {
3320 view_pos = Objects[Player_ai->target_objnum].pos;
3322 // Make camera follow explosion, but gradually slow down.
3323 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3324 view_pos = Player_obj->pos;
3325 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3326 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3329 *eye_pos = Dead_camera_pos;
3331 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3333 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3338 // if supernova shockwave
3339 if(supernova_camera_cut()){
3343 // call it dead view
3344 Viewer_mode |= VM_DEAD_VIEW;
3346 // set eye pos and orient
3347 supernova_set_view(eye_pos, eye_orient);
3349 // If already blown up, these other modes can override.
3350 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3351 Viewer_mode &= ~VM_DEAD_VIEW;
3353 Viewer_obj = Player_obj;
3355 if (Viewer_mode & VM_OTHER_SHIP) {
3356 if (Player_ai->target_objnum != -1){
3357 Viewer_obj = &Objects[Player_ai->target_objnum];
3358 last_Viewer_objnum = Player_ai->target_objnum;
3360 Viewer_mode &= ~VM_OTHER_SHIP;
3361 last_Viewer_objnum = -1;
3364 last_Viewer_objnum = -1;
3367 if (Viewer_mode & VM_EXTERNAL) {
3370 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3371 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3373 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3375 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3376 vm_vec_normalize(&eye_dir);
3377 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3380 // Modify the orientation based on head orientation.
3381 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3383 } else if ( Viewer_mode & VM_CHASE ) {
3386 if ( Viewer_obj->phys_info.speed < 0.1 )
3387 move_dir = Viewer_obj->orient.fvec;
3389 move_dir = Viewer_obj->phys_info.vel;
3390 vm_vec_normalize(&move_dir);
3393 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3394 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3395 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3396 vm_vec_normalize(&eye_dir);
3398 // JAS: I added the following code because if you slew up using
3399 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3400 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3401 // call because the up and the forward vector are the same. I fixed
3402 // it by adding in a fraction of the right vector all the time to the
3404 vector tmp_up = Viewer_obj->orient.uvec;
3405 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3407 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3410 // Modify the orientation based on head orientation.
3411 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3412 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3413 *eye_pos = Camera_pos;
3415 ship * shipp = &Ships[Player_obj->instance];
3417 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3418 vm_vec_normalize(&eye_dir);
3419 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3422 // get an eye position based upon the correct type of object
3423 switch(Viewer_obj->type){
3425 // make a call to get the eye point for the player object
3426 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3429 // make a call to get the eye point for the player object
3430 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3436 #ifdef JOHNS_DEBUG_CODE
3437 john_debug_stuff(&eye_pos, &eye_orient);
3443 apply_hud_shake(eye_orient);
3445 // setup neb2 rendering
3446 neb2_render_setup(eye_pos, eye_orient);
3450 extern void ai_debug_render_stuff();
3453 int Game_subspace_effect = 0;
3454 DCF_BOOL( subspace, Game_subspace_effect );
3456 // Does everything needed to render a frame
3457 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3461 g3_start_frame(game_zbuffer);
3462 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3464 // maybe offset the HUD (jitter stuff)
3465 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3466 HUD_set_offsets(Viewer_obj, !dont_offset);
3468 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3469 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3470 // must be done before ships are rendered
3471 if ( MULTIPLAYER_CLIENT ) {
3472 shield_point_multi_setup();
3475 if ( Game_subspace_effect ) {
3476 stars_draw(0,0,0,1);
3478 stars_draw(1,1,1,0);
3481 obj_render_all(obj_render);
3482 beam_render_all(); // render all beam weapons
3483 particle_render_all(); // render particles after everything else.
3484 trail_render_all(); // render missilie trails after everything else.
3485 mflash_render_all(); // render all muzzle flashes
3487 // Why do we not show the shield effect in these modes? Seems ok.
3488 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3492 // render nebula lightning
3495 // render local player nebula
3496 neb2_render_player();
3499 ai_debug_render_stuff();
3502 #ifndef RELEASE_REAL
3503 // game_framerate_check();
3507 extern void snd_spew_debug_info();
3508 snd_spew_debug_info();
3511 //================ END OF 3D RENDERING STUFF ====================
3515 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3516 hud_maybe_clear_head_area();
3517 anim_render_all(0, flFrametime);
3520 extern int Multi_display_netinfo;
3521 if(Multi_display_netinfo){
3522 extern void multi_display_netinfo();
3523 multi_display_netinfo();
3526 game_tst_frame_pre();
3529 do_timing_test(flFrametime);
3533 extern int OO_update_index;
3534 multi_rate_display(OO_update_index, 375, 0);
3539 extern void oo_display();
3546 //#define JOHNS_DEBUG_CODE 1
3548 #ifdef JOHNS_DEBUG_CODE
3549 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3551 //if ( keyd_pressed[KEY_LSHIFT] )
3553 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3555 model_subsystem *turret = tsys->system_info;
3557 if (turret->type == SUBSYSTEM_TURRET ) {
3559 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3561 ship_model_start(tobj);
3563 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3564 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3565 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3567 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3569 ship_model_stop(tobj);
3579 // following function for dumping frames for purposes of building trailers.
3582 // function to toggle state of dumping every frame into PCX when playing the game
3583 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3587 if ( Debug_dump_frames == 0 ) {
3589 Debug_dump_frames = 15;
3590 Debug_dump_trigger = 0;
3591 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3592 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3595 Debug_dump_frames = 0;
3596 Debug_dump_trigger = 0;
3597 gr_dump_frame_stop();
3598 dc_printf( "Frame dumping is now OFF\n" );
3604 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3608 if ( Debug_dump_frames == 0 ) {
3610 Debug_dump_frames = 15;
3611 Debug_dump_trigger = 1;
3612 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3613 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3616 Debug_dump_frames = 0;
3617 Debug_dump_trigger = 0;
3618 gr_dump_frame_stop();
3619 dc_printf( "Frame dumping is now OFF\n" );
3625 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3629 if ( Debug_dump_frames == 0 ) {
3631 Debug_dump_frames = 30;
3632 Debug_dump_trigger = 0;
3633 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3634 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3637 Debug_dump_frames = 0;
3638 Debug_dump_trigger = 0;
3639 gr_dump_frame_stop();
3640 dc_printf( "Frame dumping is now OFF\n" );
3646 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3650 if ( Debug_dump_frames == 0 ) {
3652 Debug_dump_frames = 30;
3653 Debug_dump_trigger = 1;
3654 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3655 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3658 Debug_dump_frames = 0;
3659 Debug_dump_trigger = 0;
3660 gr_dump_frame_stop();
3661 dc_printf( "Triggered frame dumping is now OFF\n" );
3667 void game_maybe_dump_frame()
3669 if ( !Debug_dump_frames ){
3673 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3680 Debug_dump_frame_num++;
3686 extern int Player_dead_state;
3688 // Flip the page and time how long it took.
3689 void game_flip_page_and_time_it()
3693 t1 = timer_get_fixed_seconds();
3695 t2 = timer_get_fixed_seconds();
3697 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3698 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3701 void game_simulation_frame()
3703 // blow ships up in multiplayer dogfight
3704 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){
3705 // blow up all non-player ships
3706 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3709 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3711 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)){
3712 moveup = GET_NEXT(moveup);
3715 shipp = &Ships[Objects[moveup->objnum].instance];
3716 sip = &Ship_info[shipp->ship_info_index];
3718 // only blow up small ships
3719 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3720 // function to simply explode a ship where it is currently at
3721 ship_self_destruct( &Objects[moveup->objnum] );
3724 moveup = GET_NEXT(moveup);
3730 // process AWACS stuff - do this first thing
3733 // single player, set Player hits_this_frame to 0
3734 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3735 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3736 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3740 supernova_process();
3741 if(supernova_active() >= 5){
3745 // fire targeting lasers now so that
3746 // 1 - created this frame
3747 // 2 - collide this frame
3748 // 3 - render this frame
3749 // 4 - ignored and deleted next frame
3750 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3752 ship_process_targeting_lasers();
3754 // do this here so that it works for multiplayer
3756 // get viewer direction
3757 int viewer_direction = PHYSICS_VIEWER_REAR;
3759 if(Viewer_mode == 0){
3760 viewer_direction = PHYSICS_VIEWER_FRONT;
3762 if(Viewer_mode & VM_PADLOCK_UP){
3763 viewer_direction = PHYSICS_VIEWER_UP;
3765 else if(Viewer_mode & VM_PADLOCK_REAR){
3766 viewer_direction = PHYSICS_VIEWER_REAR;
3768 else if(Viewer_mode & VM_PADLOCK_LEFT){
3769 viewer_direction = PHYSICS_VIEWER_LEFT;
3771 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3772 viewer_direction = PHYSICS_VIEWER_RIGHT;
3775 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3777 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3780 #define VM_PADLOCK_UP (1 << 7)
3781 #define VM_PADLOCK_REAR (1 << 8)
3782 #define VM_PADLOCK_LEFT (1 << 9)
3783 #define VM_PADLOCK_RIGHT (1 << 10)
3785 // evaluate mission departures and arrivals before we process all objects.
3786 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3788 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3789 // ships/wing packets.
3790 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3791 mission_parse_eval_stuff();
3794 // if we're an observer, move ourselves seperately from the standard physics
3795 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3796 obj_observer_move(flFrametime);
3799 // move all the objects now
3800 obj_move_all(flFrametime);
3802 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3803 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3804 // ship_check_cargo_all();
3805 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3806 mission_eval_goals();
3810 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3811 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3812 training_check_objectives();
3815 // do all interpolation now
3816 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3817 // client side processing of warping in effect stages
3818 multi_do_client_warp(flFrametime);
3820 // client side movement of an observer
3821 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3822 obj_observer_move(flFrametime);
3825 // move all objects - does interpolation now as well
3826 obj_move_all(flFrametime);
3829 // only process the message queue when the player is "in" the game
3830 if ( !Pre_player_entry ){
3831 message_queue_process(); // process any messages send to the player
3834 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3835 message_maybe_distort(); // maybe distort incoming message if comms damaged
3836 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3837 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3838 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3841 if(!(Game_mode & GM_STANDALONE_SERVER)){
3842 // process some stuff every frame (before frame is rendered)
3843 emp_process_local();
3845 hud_update_frame(); // update hud systems
3847 if (!physics_paused) {
3848 // Move particle system
3849 particle_move_all(flFrametime);
3851 // Move missile trails
3852 trail_move_all(flFrametime);
3854 // process muzzle flashes
3855 mflash_process_all();
3857 // Flash the gun flashes
3858 shipfx_flash_do_frame(flFrametime);
3860 shockwave_move_all(flFrametime); // update all the shockwaves
3863 // subspace missile strikes
3866 obj_snd_do_frame(); // update the object-linked persistant sounds
3867 game_maybe_update_sound_environment();
3868 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3870 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3872 if ( Game_subspace_effect ) {
3873 game_start_subspace_ambient_sound();
3879 // Maybe render and process the dead-popup
3880 void game_maybe_do_dead_popup(float frametime)
3882 if ( popupdead_is_active() ) {
3884 int choice = popupdead_do_frame(frametime);
3886 if ( Game_mode & GM_NORMAL ) {
3890 if(game_do_cd_mission_check(Game_current_mission_filename)){
3891 gameseq_post_event(GS_EVENT_ENTER_GAME);
3893 gameseq_post_event(GS_EVENT_MAIN_MENU);
3898 gameseq_post_event(GS_EVENT_END_GAME);
3903 if(game_do_cd_mission_check(Game_current_mission_filename)){
3904 gameseq_post_event(GS_EVENT_START_GAME);
3906 gameseq_post_event(GS_EVENT_MAIN_MENU);
3910 // this should only happen during a red alert mission
3913 Assert(The_mission.red_alert);
3914 if(!The_mission.red_alert){
3916 if(game_do_cd_mission_check(Game_current_mission_filename)){
3917 gameseq_post_event(GS_EVENT_START_GAME);
3919 gameseq_post_event(GS_EVENT_MAIN_MENU);
3924 // choose the previous mission
3925 mission_campaign_previous_mission();
3927 if(game_do_cd_mission_check(Game_current_mission_filename)){
3928 gameseq_post_event(GS_EVENT_START_GAME);
3930 gameseq_post_event(GS_EVENT_MAIN_MENU);
3941 case POPUPDEAD_DO_MAIN_HALL:
3942 multi_quit_game(PROMPT_NONE,-1);
3945 case POPUPDEAD_DO_RESPAWN:
3946 multi_respawn_normal();
3947 event_music_player_respawn();
3950 case POPUPDEAD_DO_OBSERVER:
3951 multi_respawn_observer();
3952 event_music_player_respawn_as_observer();
3961 if ( leave_popup ) {
3967 // returns true if player is actually in a game_play stats
3968 int game_actually_playing()
3972 state = gameseq_get_state();
3973 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
3979 // Draw the 2D HUD gauges
3980 void game_render_hud_2d()
3982 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
3986 HUD_render_2d(flFrametime);
3990 // Draw the 3D-dependant HUD gauges
3991 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
3993 g3_start_frame(0); // 0 = turn zbuffering off
3994 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3996 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
3997 HUD_render_3d(flFrametime);
4001 game_sunspot_process(flFrametime);
4003 // Diminish the palette effect
4004 game_flash_diminish(flFrametime);
4012 int actually_playing;
4013 fix total_time1, total_time2;
4014 fix render2_time1=0, render2_time2=0;
4015 fix render3_time1=0, render3_time2=0;
4016 fix flip_time1=0, flip_time2=0;
4017 fix clear_time1=0, clear_time2=0;
4023 if (Framerate_delay) {
4024 int start_time = timer_get_milliseconds();
4025 while (timer_get_milliseconds() < start_time + Framerate_delay)
4031 demo_do_frame_start();
4033 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4038 // start timing frame
4039 timing_frame_start();
4041 total_time1 = timer_get_fixed_seconds();
4043 // var to hold which state we are in
4044 actually_playing = game_actually_playing();
4046 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4047 if (!(Game_mode & GM_STANDALONE_SERVER)){
4048 Assert( OBJ_INDEX(Player_obj) >= 0 );
4052 if (Missiontime > Entry_delay_time){
4053 Pre_player_entry = 0;
4055 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4058 // Note: These are done even before the player enters, else buffers can overflow.
4059 if (! (Game_mode & GM_STANDALONE_SERVER)){
4063 shield_frame_init();
4065 if ( Player->control_mode != PCM_NORMAL )
4068 if ( !Pre_player_entry && actually_playing ) {
4069 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4071 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4072 game_process_keys();
4074 // don't read flying controls if we're playing a demo back
4075 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4076 read_player_controls( Player_obj, flFrametime);
4080 // if we're not the master, we may have to send the server-critical ship status button_info bits
4081 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4082 multi_maybe_send_ship_status();
4087 // Reset the whack stuff
4090 // These two lines must be outside of Pre_player_entry code,
4091 // otherwise too many lights are added.
4094 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4098 game_simulation_frame();
4100 // if not actually in a game play state, then return. This condition could only be true in
4101 // a multiplayer game.
4102 if ( !actually_playing ) {
4103 Assert( Game_mode & GM_MULTIPLAYER );
4107 if (!Pre_player_entry) {
4108 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4109 clear_time1 = timer_get_fixed_seconds();
4110 // clear the screen to black
4112 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4116 clear_time2 = timer_get_fixed_seconds();
4117 render3_time1 = timer_get_fixed_seconds();
4118 game_render_frame_setup(&eye_pos, &eye_orient);
4119 game_render_frame( &eye_pos, &eye_orient );
4121 // save the eye position and orientation
4122 if ( Game_mode & GM_MULTIPLAYER ) {
4123 Net_player->s_info.eye_pos = eye_pos;
4124 Net_player->s_info.eye_orient = eye_orient;
4127 hud_show_target_model();
4129 // check to see if we should display the death died popup
4130 if(Game_mode & GM_DEAD_BLEW_UP){
4131 if(Game_mode & GM_MULTIPLAYER){
4132 // catch the situation where we're supposed to be warping out on this transition
4133 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4134 gameseq_post_event(GS_EVENT_DEBRIEF);
4135 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4136 Player_died_popup_wait = -1;
4140 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4141 Player_died_popup_wait = -1;
4147 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4148 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4149 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4150 if(!popupdead_is_active()){
4154 Player_multi_died_check = -1;
4158 render3_time2 = timer_get_fixed_seconds();
4159 render2_time1 = timer_get_fixed_seconds();
4162 game_get_framerate();
4163 game_show_framerate();
4165 game_show_time_left();
4167 // Draw the 2D HUD gauges
4168 if(supernova_active() < 3){
4169 game_render_hud_2d();
4172 game_set_view_clip();
4174 // Draw 3D HUD gauges
4175 game_render_hud_3d(&eye_pos, &eye_orient);
4179 render2_time2 = timer_get_fixed_seconds();
4181 // maybe render and process the dead popup
4182 game_maybe_do_dead_popup(flFrametime);
4184 // start timing frame
4185 timing_frame_stop();
4186 // timing_display(30, 10);
4188 // If a regular popup is active, don't flip (popup code flips)
4189 if( !popup_running_state() ){
4190 flip_time1 = timer_get_fixed_seconds();
4191 game_flip_page_and_time_it();
4192 flip_time2 = timer_get_fixed_seconds();
4196 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4199 game_show_standalone_framerate();
4203 game_do_training_checks();
4206 // process lightning (nebula only)
4209 total_time2 = timer_get_fixed_seconds();
4211 // Got some timing numbers
4212 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4213 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4214 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4215 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4216 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4219 demo_do_frame_end();
4221 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4227 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4228 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4229 // died. This resulted in screwed up death sequences.
4231 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4232 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4233 static int timer_paused=0;
4234 static int stop_count,start_count;
4235 static int time_stopped,time_started;
4236 int saved_timestamp_ticker = -1;
4238 void game_reset_time()
4240 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4244 // Last_time = timer_get_fixed_seconds();
4250 void game_stop_time()
4252 if (timer_paused==0) {
4254 time = timer_get_fixed_seconds();
4255 // Save how much time progressed so far in the frame so we can
4256 // use it when we unpause.
4257 Last_delta_time = time - Last_time;
4259 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4260 if (Last_delta_time < 0) {
4261 #if defined(TIMER_TEST) && !defined(NDEBUG)
4262 Int3(); //get Matt!!!!
4264 Last_delta_time = 0;
4266 #if defined(TIMER_TEST) && !defined(NDEBUG)
4267 time_stopped = time;
4270 // Stop the timer_tick stuff...
4271 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4272 saved_timestamp_ticker = timestamp_ticker;
4276 #if defined(TIMER_TEST) && !defined(NDEBUG)
4281 void game_start_time()
4284 Assert(timer_paused >= 0);
4285 if (timer_paused==0) {
4287 time = timer_get_fixed_seconds();
4288 #if defined(TIMER_TEST) && !defined(NDEBUG)
4290 Int3(); //get Matt!!!!
4293 // Take current time, and set it backwards to account for time
4294 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4295 // will be correct when it goes to calculate the frametime next
4297 Last_time = time - Last_delta_time;
4298 #if defined(TIMER_TEST) && !defined(NDEBUG)
4299 time_started = time;
4302 // Restore the timer_tick stuff...
4303 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4304 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4305 timestamp_ticker = saved_timestamp_ticker;
4306 saved_timestamp_ticker = -1;
4309 #if defined(TIMER_TEST) && !defined(NDEBUG)
4315 void game_set_frametime(int state)
4318 float frame_cap_diff;
4320 thistime = timer_get_fixed_seconds();
4322 if ( Last_time == 0 )
4323 Frametime = F1_0 / 30;
4325 Frametime = thistime - Last_time;
4327 // Frametime = F1_0 / 30;
4329 fix debug_frametime = Frametime; // Just used to display frametime.
4331 // If player hasn't entered mission yet, make frame take 1/4 second.
4332 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4335 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4337 fix frame_speed = F1_0 / Debug_dump_frames;
4339 if (Frametime > frame_speed ){
4340 nprintf(("warning","slow frame: %x\n",Frametime));
4343 thistime = timer_get_fixed_seconds();
4344 Frametime = thistime - Last_time;
4345 } while (Frametime < frame_speed );
4347 Frametime = frame_speed;
4351 Assert( Framerate_cap > 0 );
4353 // Cap the framerate so it doesn't get too high.
4357 cap = F1_0/Framerate_cap;
4358 if (Frametime < cap) {
4359 thistime = cap - Frametime;
4360 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4361 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4363 thistime = timer_get_fixed_seconds();
4367 if((Game_mode & GM_STANDALONE_SERVER) &&
4368 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4370 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4371 Sleep((DWORD)(frame_cap_diff*1000));
4373 thistime += fl2f((frame_cap_diff));
4375 Frametime = thistime - Last_time;
4378 // If framerate is too low, cap it.
4379 if (Frametime > MAX_FRAMETIME) {
4381 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4383 // to remove warnings in release build
4384 debug_frametime = fl2f(flFrametime);
4386 Frametime = MAX_FRAMETIME;
4389 Frametime = fixmul(Frametime, Game_time_compression);
4391 Last_time = thistime;
4392 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4394 flFrametime = f2fl(Frametime);
4395 //if(!(Game_mode & GM_PLAYING_DEMO)){
4396 timestamp_inc(flFrametime);
4398 /* if ((Framecount > 0) && (Framecount < 10)) {
4399 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4404 // This is called from game_do_frame(), and from navmap_do_frame()
4405 void game_update_missiontime()
4407 // TODO JAS: Put in if and move this into game_set_frametime,
4408 // fix navmap to call game_stop/start_time
4409 //if ( !timer_paused )
4410 Missiontime += Frametime;
4413 void game_do_frame()
4415 game_set_frametime(GS_STATE_GAME_PLAY);
4416 game_update_missiontime();
4418 if (Game_mode & GM_STANDALONE_SERVER) {
4419 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4422 if ( game_single_step && (last_single_step == game_single_step) ) {
4423 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4424 while( key_checkch() == 0 )
4426 os_set_title( XSTR( "FreeSpace", 171) );
4427 Last_time = timer_get_fixed_seconds();
4430 last_single_step = game_single_step;
4432 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4433 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4437 Keep_mouse_centered = 0;
4438 monitor_update(); // Update monitor variables
4441 void multi_maybe_do_frame()
4443 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4448 int Joymouse_button_status = 0;
4450 // Flush all input devices
4458 Joymouse_button_status = 0;
4460 //mprintf(("Game flush!\n" ));
4463 // function for multiplayer only which calls game_do_state_common() when running the
4465 void game_do_dc_networking()
4467 Assert( Game_mode & GM_MULTIPLAYER );
4469 game_do_state_common( gameseq_get_state() );
4472 // Call this whenever in a loop, or when you need to check for a keystroke.
4473 int game_check_key()
4479 // convert keypad enter to normal enter
4480 if ((k & KEY_MASK) == KEY_PADENTER)
4481 k = (k & ~KEY_MASK) | KEY_ENTER;
4488 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4489 static int Demo_show_trailer_timestamp = 0;
4491 void demo_reset_trailer_timer()
4493 Demo_show_trailer_timestamp = timer_get_milliseconds();
4496 void demo_maybe_show_trailer(int k)
4499 // if key pressed, reset demo trailer timer
4501 demo_reset_trailer_timer();
4505 // if mouse moved, reset demo trailer timer
4508 mouse_get_delta(&dx, &dy);
4509 if ( (dx > 0) || (dy > 0) ) {
4510 demo_reset_trailer_timer();
4514 // if joystick has moved, reset demo trailer timer
4517 joy_get_delta(&dx, &dy);
4518 if ( (dx > 0) || (dy > 0) ) {
4519 demo_reset_trailer_timer();
4523 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4524 // the low-level code. Ugly, I know... but was the simplest and most
4527 // if 30 seconds since last demo trailer time reset, launch movie
4528 if ( os_foreground() ) {
4529 int now = timer_get_milliseconds();
4530 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4531 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4533 movie_play( NOX("fstrailer2.mve") );
4534 demo_reset_trailer_timer();
4542 // same as game_check_key(), except this is used while actually in the game. Since there
4543 // generally are differences between game control keys and general UI keys, makes sense to
4544 // have seperate functions for each case. If you are not checking a game control while in a
4545 // mission, you should probably be using game_check_key() instead.
4550 if (!os_foreground()) {
4555 // If we're in a single player game, pause it.
4556 if (!(Game_mode & GM_MULTIPLAYER)){
4557 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4558 game_process_pause_key();
4566 demo_maybe_show_trailer(k);
4569 // Move the mouse cursor with the joystick.
4570 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4571 // Move the mouse cursor with the joystick
4575 joy_get_pos( &jx, &jy, &jz, &jr );
4577 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4578 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4581 mouse_get_real_pos( &mx, &my );
4582 mouse_set_pos( mx+dx, my+dy );
4587 m = mouse_down(MOUSE_LEFT_BUTTON);
4589 if ( j != Joymouse_button_status ) {
4590 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4591 Joymouse_button_status = j;
4593 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4594 } else if ( (!j) && (m) ) {
4595 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4600 // if we should be ignoring keys because of some multiplayer situations
4601 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4605 // If a popup is running, don't process all the Fn keys
4606 if( popup_active() ) {
4610 state = gameseq_get_state();
4612 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4615 case KEY_DEBUGGED + KEY_BACKSP:
4620 launch_context_help();
4625 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4627 // don't allow f2 while warping out in multiplayer
4628 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4633 case GS_STATE_INITIAL_PLAYER_SELECT:
4634 case GS_STATE_OPTIONS_MENU:
4635 case GS_STATE_HUD_CONFIG:
4636 case GS_STATE_CONTROL_CONFIG:
4637 case GS_STATE_DEATH_DIED:
4638 case GS_STATE_DEATH_BLEW_UP:
4639 case GS_STATE_VIEW_MEDALS:
4643 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4650 // hotkey selection screen -- only valid from briefing and beyond.
4653 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) ) {
4654 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4660 case KEY_DEBUGGED + KEY_F3:
4661 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4664 case KEY_DEBUGGED + KEY_F4:
4665 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4669 if(Game_mode & GM_MULTIPLAYER){
4670 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4671 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4675 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4676 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4682 case KEY_ESC | KEY_SHIFTED:
4683 // make sure to quit properly out of multiplayer
4684 if(Game_mode & GM_MULTIPLAYER){
4685 multi_quit_game(PROMPT_NONE);
4688 gameseq_post_event( GS_EVENT_QUIT_GAME );
4693 case KEY_DEBUGGED + KEY_P:
4696 case KEY_PRINT_SCRN:
4703 sprintf( tmp_name, NOX("screen%02d"), counter );
4705 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4706 gr_print_screen(tmp_name);
4714 case KEY_SHIFTED | KEY_ENTER: {
4716 #if !defined(NDEBUG)
4718 if ( Game_mode & GM_NORMAL ){
4722 // if we're in multiplayer mode, do some special networking
4723 if(Game_mode & GM_MULTIPLAYER){
4724 debug_console(game_do_dc_networking);
4731 if ( Game_mode & GM_NORMAL )
4745 gameseq_post_event(GS_EVENT_QUIT_GAME);
4748 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4751 void camera_set_position( vector *pos )
4756 void camera_set_orient( matrix *orient )
4758 Camera_orient = *orient;
4761 void camera_set_velocity( vector *vel, int instantaneous )
4763 Camera_desired_velocity.x = 0.0f;
4764 Camera_desired_velocity.y = 0.0f;
4765 Camera_desired_velocity.z = 0.0f;
4767 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4768 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4769 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4771 if ( instantaneous ) {
4772 Camera_velocity = Camera_desired_velocity;
4780 vector new_vel, delta_pos;
4782 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4783 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4784 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4786 Camera_velocity = new_vel;
4788 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4790 vm_vec_add2( &Camera_pos, &delta_pos );
4792 float ot = Camera_time+0.0f;
4794 Camera_time += flFrametime;
4796 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4799 tmp.z = 4.739f; // always go this fast forward.
4801 // pick x and y velocities so they are always on a
4802 // circle with a 25 m radius.
4804 float tmp_angle = frand()*PI2;
4806 tmp.x = 22.0f * (float)sin(tmp_angle);
4807 tmp.y = -22.0f * (float)cos(tmp_angle);
4809 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4811 //mprintf(( "Changing velocity!\n" ));
4812 camera_set_velocity( &tmp, 0 );
4815 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4816 vector tmp = { 0.0f, 0.0f, 0.0f };
4817 camera_set_velocity( &tmp, 0 );
4822 void end_demo_campaign_do()
4824 #if defined(FS2_DEMO)
4825 // show upsell screens
4826 demo_upsell_show_screens();
4827 #elif defined(OEM_BUILD)
4828 // show oem upsell screens
4829 oem_upsell_show_screens();
4832 // drop into main hall
4833 gameseq_post_event( GS_EVENT_MAIN_MENU );
4836 // All code to process events. This is the only place
4837 // that you should change the state of the game.
4838 void game_process_event( int current_state, int event )
4840 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4843 case GS_EVENT_SIMULATOR_ROOM:
4844 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4847 case GS_EVENT_MAIN_MENU:
4848 gameseq_set_state(GS_STATE_MAIN_MENU);
4851 case GS_EVENT_OPTIONS_MENU:
4852 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4855 case GS_EVENT_BARRACKS_MENU:
4856 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4859 case GS_EVENT_TECH_MENU:
4860 gameseq_set_state(GS_STATE_TECH_MENU);
4863 case GS_EVENT_TRAINING_MENU:
4864 gameseq_set_state(GS_STATE_TRAINING_MENU);
4867 case GS_EVENT_START_GAME:
4868 Select_default_ship = 0;
4869 Player_multi_died_check = -1;
4870 gameseq_set_state(GS_STATE_CMD_BRIEF);
4873 case GS_EVENT_START_BRIEFING:
4874 gameseq_set_state(GS_STATE_BRIEFING);
4877 case GS_EVENT_DEBRIEF:
4878 // did we end the campaign in the main freespace 2 single player campaign?
4879 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4880 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4882 gameseq_set_state(GS_STATE_DEBRIEF);
4885 Player_multi_died_check = -1;
4888 case GS_EVENT_SHIP_SELECTION:
4889 gameseq_set_state( GS_STATE_SHIP_SELECT );
4892 case GS_EVENT_WEAPON_SELECTION:
4893 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4896 case GS_EVENT_ENTER_GAME:
4898 // maybe start recording a demo
4900 demo_start_record("test.fsd");
4904 if (Game_mode & GM_MULTIPLAYER) {
4905 // if we're respawning, make sure we change the view mode so that the hud shows up
4906 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4910 gameseq_set_state(GS_STATE_GAME_PLAY);
4912 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4915 Player_multi_died_check = -1;
4917 // clear multiplayer button info
4918 extern button_info Multi_ship_status_bi;
4919 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4921 Start_time = f2fl(timer_get_approx_seconds());
4923 mprintf(("Entering game at time = %7.3f\n", Start_time));
4927 case GS_EVENT_START_GAME_QUICK:
4928 Select_default_ship = 1;
4929 gameseq_post_event(GS_EVENT_ENTER_GAME);
4933 case GS_EVENT_END_GAME:
4934 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4935 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4936 gameseq_set_state(GS_STATE_MAIN_MENU);
4941 Player_multi_died_check = -1;
4944 case GS_EVENT_QUIT_GAME:
4945 main_hall_stop_music();
4946 main_hall_stop_ambient();
4947 gameseq_set_state(GS_STATE_QUIT_GAME);
4949 Player_multi_died_check = -1;
4952 case GS_EVENT_GAMEPLAY_HELP:
4953 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
4956 case GS_EVENT_PAUSE_GAME:
4957 gameseq_push_state(GS_STATE_GAME_PAUSED);
4960 case GS_EVENT_DEBUG_PAUSE_GAME:
4961 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
4964 case GS_EVENT_TRAINING_PAUSE:
4965 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
4968 case GS_EVENT_PREVIOUS_STATE:
4969 gameseq_pop_state();
4972 case GS_EVENT_TOGGLE_FULLSCREEN:
4973 #ifndef HARDWARE_ONLY
4975 if ( gr_screen.mode == GR_SOFTWARE ) {
4976 gr_init( GR_640, GR_DIRECTDRAW );
4977 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
4978 gr_init( GR_640, GR_SOFTWARE );
4984 case GS_EVENT_TOGGLE_GLIDE:
4986 if ( gr_screen.mode != GR_GLIDE ) {
4987 gr_init( GR_640, GR_GLIDE );
4989 gr_init( GR_640, GR_SOFTWARE );
4994 case GS_EVENT_LOAD_MISSION_MENU:
4995 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
4998 case GS_EVENT_MISSION_LOG_SCROLLBACK:
4999 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5002 case GS_EVENT_HUD_CONFIG:
5003 gameseq_push_state( GS_STATE_HUD_CONFIG );
5006 case GS_EVENT_CONTROL_CONFIG:
5007 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5010 case GS_EVENT_DEATH_DIED:
5011 gameseq_set_state( GS_STATE_DEATH_DIED );
5014 case GS_EVENT_DEATH_BLEW_UP:
5015 if ( current_state == GS_STATE_DEATH_DIED ) {
5016 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5017 event_music_player_death();
5019 // multiplayer clients set their extra check here
5020 if(Game_mode & GM_MULTIPLAYER){
5021 // set the multi died absolute last chance check
5022 Player_multi_died_check = time(NULL);
5025 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5029 case GS_EVENT_NEW_CAMPAIGN:
5030 if (!mission_load_up_campaign()){
5031 readyroom_continue_campaign();
5034 Player_multi_died_check = -1;
5037 case GS_EVENT_CAMPAIGN_CHEAT:
5038 if (!mission_load_up_campaign()){
5040 // bash campaign value
5041 extern char Main_hall_campaign_cheat[512];
5044 // look for the mission
5045 for(idx=0; idx<Campaign.num_missions; idx++){
5046 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5047 Campaign.next_mission = idx;
5048 Campaign.prev_mission = idx - 1;
5055 readyroom_continue_campaign();
5058 Player_multi_died_check = -1;
5061 case GS_EVENT_CAMPAIGN_ROOM:
5062 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5065 case GS_EVENT_CMD_BRIEF:
5066 gameseq_set_state(GS_STATE_CMD_BRIEF);
5069 case GS_EVENT_RED_ALERT:
5070 gameseq_set_state(GS_STATE_RED_ALERT);
5073 case GS_EVENT_CREDITS:
5074 gameseq_set_state( GS_STATE_CREDITS );
5077 case GS_EVENT_VIEW_MEDALS:
5078 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5081 case GS_EVENT_SHOW_GOALS:
5082 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5085 case GS_EVENT_HOTKEY_SCREEN:
5086 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5089 // multiplayer stuff follow these comments
5091 case GS_EVENT_MULTI_JOIN_GAME:
5092 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5095 case GS_EVENT_MULTI_HOST_SETUP:
5096 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5099 case GS_EVENT_MULTI_CLIENT_SETUP:
5100 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5103 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5104 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5107 case GS_EVENT_MULTI_STD_WAIT:
5108 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5111 case GS_EVENT_STANDALONE_MAIN:
5112 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5115 case GS_EVENT_MULTI_PAUSE:
5116 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5119 case GS_EVENT_INGAME_PRE_JOIN:
5120 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5123 case GS_EVENT_EVENT_DEBUG:
5124 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5127 // Start a warpout where player automatically goes 70 no matter what
5128 // and can't cancel out of it.
5129 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5130 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5132 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5133 Player->saved_viewer_mode = Viewer_mode;
5134 Player->control_mode = PCM_WARPOUT_STAGE1;
5135 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5136 Warpout_time = 0.0f; // Start timer!
5139 case GS_EVENT_PLAYER_WARPOUT_START:
5140 if ( Player->control_mode != PCM_NORMAL ) {
5141 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5143 Player->saved_viewer_mode = Viewer_mode;
5144 Player->control_mode = PCM_WARPOUT_STAGE1;
5145 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5146 Warpout_time = 0.0f; // Start timer!
5147 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5151 case GS_EVENT_PLAYER_WARPOUT_STOP:
5152 if ( Player->control_mode != PCM_NORMAL ) {
5153 if ( !Warpout_forced ) { // cannot cancel forced warpout
5154 Player->control_mode = PCM_NORMAL;
5155 Viewer_mode = Player->saved_viewer_mode;
5156 hud_subspace_notify_abort();
5157 mprintf(( "Player put back to normal mode.\n" ));
5158 if ( Warpout_sound > -1 ) {
5159 snd_stop( Warpout_sound );
5166 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5167 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5168 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5169 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5171 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5172 shipfx_warpout_start( Player_obj );
5173 Player->control_mode = PCM_WARPOUT_STAGE2;
5174 Player->saved_viewer_mode = Viewer_mode;
5175 Viewer_mode |= VM_WARP_CHASE;
5177 vector tmp = Player_obj->pos;
5179 ship_get_eye( &tmp, &tmp_m, Player_obj );
5180 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5181 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5182 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5184 camera_set_position( &tmp );
5185 camera_set_orient( &Player_obj->orient );
5186 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5188 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5189 camera_set_velocity( &tmp_vel, 1);
5193 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5194 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5195 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5196 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5198 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5199 Player->control_mode = PCM_WARPOUT_STAGE3;
5203 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5204 mprintf(( "Player warped out. Going to debriefing!\n" ));
5205 Player->control_mode = PCM_NORMAL;
5206 Viewer_mode = Player->saved_viewer_mode;
5209 // we have a special debriefing screen for multiplayer furballs
5210 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5211 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5213 // do the normal debriefing for all other situations
5215 gameseq_post_event(GS_EVENT_DEBRIEF);
5219 case GS_EVENT_STANDALONE_POSTGAME:
5220 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5223 case GS_EVENT_INITIAL_PLAYER_SELECT:
5224 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5227 case GS_EVENT_GAME_INIT:
5228 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5229 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5231 // see if the command line option has been set to use the last pilot, and act acoordingly
5232 if( player_select_get_last_pilot() ) {
5233 // always enter the main menu -- do the automatic network startup stuff elsewhere
5234 // so that we still have valid checks for networking modes, etc.
5235 gameseq_set_state(GS_STATE_MAIN_MENU);
5237 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5242 case GS_EVENT_MULTI_MISSION_SYNC:
5243 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5246 case GS_EVENT_MULTI_START_GAME:
5247 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5250 case GS_EVENT_MULTI_HOST_OPTIONS:
5251 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5254 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5255 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5258 case GS_EVENT_TEAM_SELECT:
5259 gameseq_set_state(GS_STATE_TEAM_SELECT);
5262 case GS_EVENT_END_CAMPAIGN:
5263 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5266 case GS_EVENT_END_DEMO:
5267 gameseq_set_state(GS_STATE_END_DEMO);
5270 case GS_EVENT_LOOP_BRIEF:
5271 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5280 // Called when a state is being left.
5281 // The current state is still at old_state, but as soon as
5282 // this function leaves, then the current state will become
5283 // new state. You should never try to change the state
5284 // in here... if you think you need to, you probably really
5285 // need to post an event, not change the state.
5286 void game_leave_state( int old_state, int new_state )
5288 int end_mission = 1;
5290 switch (new_state) {
5291 case GS_STATE_GAME_PAUSED:
5292 case GS_STATE_DEBUG_PAUSED:
5293 case GS_STATE_OPTIONS_MENU:
5294 case GS_STATE_CONTROL_CONFIG:
5295 case GS_STATE_MISSION_LOG_SCROLLBACK:
5296 case GS_STATE_DEATH_DIED:
5297 case GS_STATE_SHOW_GOALS:
5298 case GS_STATE_HOTKEY_SCREEN:
5299 case GS_STATE_MULTI_PAUSED:
5300 case GS_STATE_TRAINING_PAUSED:
5301 case GS_STATE_EVENT_DEBUG:
5302 case GS_STATE_GAMEPLAY_HELP:
5303 end_mission = 0; // these events shouldn't end a mission
5307 switch (old_state) {
5308 case GS_STATE_BRIEFING:
5309 brief_stop_voices();
5310 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5311 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5312 && (new_state != GS_STATE_TEAM_SELECT) ){
5313 common_select_close();
5314 if ( new_state == GS_STATE_MAIN_MENU ) {
5315 freespace_stop_mission();
5319 // COMMAND LINE OPTION
5320 if (Cmdline_multi_stream_chat_to_file){
5321 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5322 cfclose(Multi_chat_stream);
5326 case GS_STATE_DEBRIEF:
5327 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5332 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5333 multi_df_debrief_close();
5336 case GS_STATE_LOAD_MISSION_MENU:
5337 mission_load_menu_close();
5340 case GS_STATE_SIMULATOR_ROOM:
5344 case GS_STATE_CAMPAIGN_ROOM:
5345 campaign_room_close();
5348 case GS_STATE_CMD_BRIEF:
5349 if (new_state == GS_STATE_OPTIONS_MENU) {
5354 if (new_state == GS_STATE_MAIN_MENU)
5355 freespace_stop_mission();
5360 case GS_STATE_RED_ALERT:
5364 case GS_STATE_SHIP_SELECT:
5365 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5366 new_state != GS_STATE_HOTKEY_SCREEN &&
5367 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5368 common_select_close();
5369 if ( new_state == GS_STATE_MAIN_MENU ) {
5370 freespace_stop_mission();
5375 case GS_STATE_WEAPON_SELECT:
5376 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5377 new_state != GS_STATE_HOTKEY_SCREEN &&
5378 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5379 common_select_close();
5380 if ( new_state == GS_STATE_MAIN_MENU ) {
5381 freespace_stop_mission();
5386 case GS_STATE_TEAM_SELECT:
5387 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5388 new_state != GS_STATE_HOTKEY_SCREEN &&
5389 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5390 common_select_close();
5391 if ( new_state == GS_STATE_MAIN_MENU ) {
5392 freespace_stop_mission();
5397 case GS_STATE_MAIN_MENU:
5398 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5405 case GS_STATE_OPTIONS_MENU:
5406 //game_start_time();
5407 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5408 multi_join_clear_game_list();
5410 options_menu_close();
5413 case GS_STATE_BARRACKS_MENU:
5414 if(new_state != GS_STATE_VIEW_MEDALS){
5419 case GS_STATE_MISSION_LOG_SCROLLBACK:
5420 hud_scrollback_close();
5423 case GS_STATE_TRAINING_MENU:
5424 training_menu_close();
5427 case GS_STATE_GAME_PLAY:
5428 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5429 player_save_target_and_weapon_link_prefs();
5430 game_stop_looped_sounds();
5433 sound_env_disable();
5434 joy_ff_stop_effects();
5436 // stop game time under certain conditions
5437 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5442 // shut down any recording or playing demos
5447 // when in multiplayer and going back to the main menu, send a leave game packet
5448 // right away (before calling stop mission). stop_mission was taking to long to
5449 // close mission down and I want people to get notified ASAP.
5450 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5451 multi_quit_game(PROMPT_NONE);
5454 freespace_stop_mission();
5455 Game_time_compression = F1_0;
5459 case GS_STATE_TECH_MENU:
5463 case GS_STATE_TRAINING_PAUSED:
5464 Training_num_lines = 0;
5465 // fall through to GS_STATE_GAME_PAUSED
5467 case GS_STATE_GAME_PAUSED:
5469 if ( end_mission ) {
5474 case GS_STATE_DEBUG_PAUSED:
5477 pause_debug_close();
5481 case GS_STATE_HUD_CONFIG:
5485 // join/start a game
5486 case GS_STATE_MULTI_JOIN_GAME:
5487 if(new_state != GS_STATE_OPTIONS_MENU){
5488 multi_join_game_close();
5492 case GS_STATE_MULTI_HOST_SETUP:
5493 case GS_STATE_MULTI_CLIENT_SETUP:
5494 // if this is just the host going into the options screen, don't do anything
5495 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5499 // close down the proper state
5500 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5501 multi_create_game_close();
5503 multi_game_client_setup_close();
5506 // COMMAND LINE OPTION
5507 if (Cmdline_multi_stream_chat_to_file){
5508 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5509 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5510 cfclose(Multi_chat_stream);
5515 case GS_STATE_CONTROL_CONFIG:
5516 control_config_close();
5519 case GS_STATE_DEATH_DIED:
5520 Game_mode &= ~GM_DEAD_DIED;
5522 // early end while respawning or blowing up in a multiplayer game
5523 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5525 freespace_stop_mission();
5529 case GS_STATE_DEATH_BLEW_UP:
5530 Game_mode &= ~GM_DEAD_BLEW_UP;
5532 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5533 // to determine if I should do anything.
5534 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5536 freespace_stop_mission();
5539 // if we are not respawing as an observer or as a player, our new state will not
5540 // be gameplay state.
5541 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5542 game_stop_time(); // hasn't been called yet!!
5543 freespace_stop_mission();
5549 case GS_STATE_CREDITS:
5553 case GS_STATE_VIEW_MEDALS:
5557 case GS_STATE_SHOW_GOALS:
5558 mission_show_goals_close();
5561 case GS_STATE_HOTKEY_SCREEN:
5562 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5563 mission_hotkey_close();
5567 case GS_STATE_MULTI_MISSION_SYNC:
5568 // if we're moving into the options menu, don't do anything
5569 if(new_state == GS_STATE_OPTIONS_MENU){
5573 Assert( Game_mode & GM_MULTIPLAYER );
5575 if ( new_state == GS_STATE_GAME_PLAY ){
5576 // palette_restore_palette();
5578 // change a couple of flags to indicate our state!!!
5579 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5580 send_netplayer_update_packet();
5582 // set the game mode
5583 Game_mode |= GM_IN_MISSION;
5587 case GS_STATE_VIEW_CUTSCENES:
5588 cutscenes_screen_close();
5591 case GS_STATE_MULTI_STD_WAIT:
5592 multi_standalone_wait_close();
5595 case GS_STATE_STANDALONE_MAIN:
5596 standalone_main_close();
5597 if(new_state == GS_STATE_MULTI_STD_WAIT){
5598 init_multiplayer_stats();
5602 case GS_STATE_MULTI_PAUSED:
5603 // if ( end_mission ){
5608 case GS_STATE_INGAME_PRE_JOIN:
5609 multi_ingame_select_close();
5612 case GS_STATE_STANDALONE_POSTGAME:
5613 multi_standalone_postgame_close();
5616 case GS_STATE_INITIAL_PLAYER_SELECT:
5617 player_select_close();
5620 case GS_STATE_MULTI_START_GAME:
5621 multi_start_game_close();
5624 case GS_STATE_MULTI_HOST_OPTIONS:
5625 multi_host_options_close();
5628 case GS_STATE_END_OF_CAMPAIGN:
5629 mission_campaign_end_close();
5632 case GS_STATE_LOOP_BRIEF:
5638 // Called when a state is being entered.
5639 // The current state is set to the state we're entering at
5640 // this point, and old_state is set to the state we're coming
5641 // from. You should never try to change the state
5642 // in here... if you think you need to, you probably really
5643 // need to post an event, not change the state.
5645 void game_enter_state( int old_state, int new_state )
5647 switch (new_state) {
5648 case GS_STATE_MAIN_MENU:
5649 // in multiplayer mode, be sure that we are not doing networking anymore.
5650 if ( Game_mode & GM_MULTIPLAYER ) {
5651 Assert( Net_player != NULL );
5652 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5655 Game_time_compression = F1_0;
5657 // determine which ship this guy is currently based on
5658 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5661 if (Player->on_bastion) {
5669 case GS_STATE_BRIEFING:
5670 main_hall_stop_music();
5671 main_hall_stop_ambient();
5673 if (Game_mode & GM_NORMAL) {
5674 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5675 // MWA: or from options or hotkey screens
5676 // JH: or if the command brief state already did this
5677 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5678 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5679 && (old_state != GS_STATE_CMD_BRIEF) ) {
5680 if ( !game_start_mission() ) // this should put us into a new state on failure!
5684 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5685 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5686 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5688 Game_time_compression = F1_0;
5690 if ( red_alert_mission() ) {
5691 gameseq_post_event(GS_EVENT_RED_ALERT);
5698 case GS_STATE_DEBRIEF:
5699 game_stop_looped_sounds();
5700 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5701 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5706 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5707 multi_df_debrief_init();
5710 case GS_STATE_LOAD_MISSION_MENU:
5711 mission_load_menu_init();
5714 case GS_STATE_SIMULATOR_ROOM:
5718 case GS_STATE_CAMPAIGN_ROOM:
5719 campaign_room_init();
5722 case GS_STATE_RED_ALERT:
5723 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5727 case GS_STATE_CMD_BRIEF: {
5728 int team_num = 0; // team number used as index for which cmd brief to use.
5730 if (old_state == GS_STATE_OPTIONS_MENU) {
5734 main_hall_stop_music();
5735 main_hall_stop_ambient();
5737 if (Game_mode & GM_NORMAL) {
5738 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5739 // MWA: or from options or hotkey screens
5740 // JH: or if the command brief state already did this
5741 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5742 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5743 if ( !game_start_mission() ) // this should put us into a new state on failure!
5748 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5749 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5750 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5752 cmd_brief_init(team_num);
5758 case GS_STATE_SHIP_SELECT:
5762 case GS_STATE_WEAPON_SELECT:
5763 weapon_select_init();
5766 case GS_STATE_TEAM_SELECT:
5770 case GS_STATE_GAME_PAUSED:
5775 case GS_STATE_DEBUG_PAUSED:
5776 // game_stop_time();
5777 // os_set_title("FreeSpace - PAUSED");
5780 case GS_STATE_TRAINING_PAUSED:
5787 case GS_STATE_OPTIONS_MENU:
5789 options_menu_init();
5792 case GS_STATE_GAME_PLAY:
5793 // coming from the gameplay state or the main menu, we might need to load the mission
5794 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5795 if ( !game_start_mission() ) // this should put us into a new state.
5800 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5801 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5802 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5803 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5804 (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) ) {
5805 // JAS: Used to do all paging here.
5809 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5813 main_hall_stop_music();
5814 main_hall_stop_ambient();
5815 event_music_first_pattern(); // start the first pattern
5818 // special code that restores player ship selection and weapons loadout when doing a quick start
5819 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5820 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5821 wss_direct_restore_loadout();
5825 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5826 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5827 event_music_first_pattern(); // start the first pattern
5830 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5831 event_music_first_pattern(); // start the first pattern
5833 player_restore_target_and_weapon_link_prefs();
5835 Game_mode |= GM_IN_MISSION;
5838 // required to truely make mouse deltas zeroed in debug mouse code
5839 void mouse_force_pos(int x, int y);
5840 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5845 // only start time if in single player, or coming from multi wait state
5848 (Game_mode & GM_NORMAL) &&
5849 (old_state != GS_STATE_VIEW_CUTSCENES)
5851 (Game_mode & GM_MULTIPLAYER) && (
5852 (old_state == GS_STATE_MULTI_PAUSED) ||
5853 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5859 // when coming from the multi paused state, reset the timestamps
5860 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5861 multi_reset_timestamps();
5864 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5865 // initialize all object update details
5866 multi_oo_gameplay_init();
5869 // under certain circumstances, the server should reset the object update rate limiting stuff
5870 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5871 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5873 // reinitialize the rate limiting system for all clients
5874 multi_oo_rate_init_all();
5877 // multiplayer clients should always re-initialize their control info rate limiting system
5878 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5879 multi_oo_rate_init_all();
5883 if(Game_mode & GM_MULTIPLAYER){
5884 multi_ping_reset_players();
5887 Game_subspace_effect = 0;
5888 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5889 Game_subspace_effect = 1;
5890 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5891 game_start_subspace_ambient_sound();
5895 sound_env_set(&Game_sound_env);
5896 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5898 // clear multiplayer button info i
5899 extern button_info Multi_ship_status_bi;
5900 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5903 case GS_STATE_HUD_CONFIG:
5907 case GS_STATE_MULTI_JOIN_GAME:
5908 multi_join_clear_game_list();
5910 if (old_state != GS_STATE_OPTIONS_MENU) {
5911 multi_join_game_init();
5916 case GS_STATE_MULTI_HOST_SETUP:
5917 // don't reinitialize if we're coming back from the host options screen
5918 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5919 multi_create_game_init();
5924 case GS_STATE_MULTI_CLIENT_SETUP:
5925 if (old_state != GS_STATE_OPTIONS_MENU) {
5926 multi_game_client_setup_init();
5931 case GS_STATE_CONTROL_CONFIG:
5932 control_config_init();
5935 case GS_STATE_TECH_MENU:
5939 case GS_STATE_BARRACKS_MENU:
5940 if(old_state != GS_STATE_VIEW_MEDALS){
5945 case GS_STATE_MISSION_LOG_SCROLLBACK:
5946 hud_scrollback_init();
5949 case GS_STATE_DEATH_DIED:
5950 Player_died_time = timestamp(10);
5952 if(!(Game_mode & GM_MULTIPLAYER)){
5953 player_show_death_message();
5955 Game_mode |= GM_DEAD_DIED;
5958 case GS_STATE_DEATH_BLEW_UP:
5959 if ( !popupdead_is_active() ) {
5960 Player_ai->target_objnum = -1;
5963 // stop any local EMP effect
5966 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
5967 Game_mode |= GM_DEAD_BLEW_UP;
5968 Show_viewing_from_self = 0;
5970 // timestamp how long we should wait before displaying the died popup
5971 if ( !popupdead_is_active() ) {
5972 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
5976 case GS_STATE_GAMEPLAY_HELP:
5977 gameplay_help_init();
5980 case GS_STATE_CREDITS:
5981 main_hall_stop_music();
5982 main_hall_stop_ambient();
5986 case GS_STATE_VIEW_MEDALS:
5987 medal_main_init(Player);
5990 case GS_STATE_SHOW_GOALS:
5991 mission_show_goals_init();
5994 case GS_STATE_HOTKEY_SCREEN:
5995 mission_hotkey_init();
5998 case GS_STATE_MULTI_MISSION_SYNC:
5999 // if we're coming from the options screen, don't do any
6000 if(old_state == GS_STATE_OPTIONS_MENU){
6004 switch(Multi_sync_mode){
6005 case MULTI_SYNC_PRE_BRIEFING:
6006 // if moving from game forming to the team select state
6009 case MULTI_SYNC_POST_BRIEFING:
6010 // if moving from briefing into the mission itself
6013 // tell everyone that we're now loading data
6014 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6015 send_netplayer_update_packet();
6017 // JAS: Used to do all paging here!!!!
6019 Net_player->state = NETPLAYER_STATE_WAITING;
6020 send_netplayer_update_packet();
6022 Game_time_compression = F1_0;
6024 case MULTI_SYNC_INGAME:
6030 case GS_STATE_VIEW_CUTSCENES:
6031 cutscenes_screen_init();
6034 case GS_STATE_MULTI_STD_WAIT:
6035 multi_standalone_wait_init();
6038 case GS_STATE_STANDALONE_MAIN:
6039 // don't initialize if we're coming from one of these 2 states unless there are no
6040 // players left (reset situation)
6041 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6042 standalone_main_init();
6046 case GS_STATE_MULTI_PAUSED:
6050 case GS_STATE_INGAME_PRE_JOIN:
6051 multi_ingame_select_init();
6054 case GS_STATE_STANDALONE_POSTGAME:
6055 multi_standalone_postgame_init();
6058 case GS_STATE_INITIAL_PLAYER_SELECT:
6059 player_select_init();
6062 case GS_STATE_MULTI_START_GAME:
6063 multi_start_game_init();
6066 case GS_STATE_MULTI_HOST_OPTIONS:
6067 multi_host_options_init();
6070 case GS_STATE_END_OF_CAMPAIGN:
6071 mission_campaign_end_init();
6074 case GS_STATE_LOOP_BRIEF:
6081 // do stuff that may need to be done regardless of state
6082 void game_do_state_common(int state,int no_networking)
6084 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6085 snd_do_frame(); // update sound system
6086 event_music_do_frame(); // music needs to play across many states
6088 multi_log_process();
6090 if (no_networking) {
6094 // maybe do a multiplayer frame based on game mode and state type
6095 if (Game_mode & GM_MULTIPLAYER) {
6097 case GS_STATE_OPTIONS_MENU:
6098 case GS_STATE_GAMEPLAY_HELP:
6099 case GS_STATE_HOTKEY_SCREEN:
6100 case GS_STATE_HUD_CONFIG:
6101 case GS_STATE_CONTROL_CONFIG:
6102 case GS_STATE_MISSION_LOG_SCROLLBACK:
6103 case GS_STATE_SHOW_GOALS:
6104 case GS_STATE_VIEW_CUTSCENES:
6105 case GS_STATE_EVENT_DEBUG:
6106 multi_maybe_do_frame();
6110 game_do_networking();
6114 // Called once a frame.
6115 // You should never try to change the state
6116 // in here... if you think you need to, you probably really
6117 // need to post an event, not change the state.
6118 int Game_do_state_should_skip = 0;
6119 void game_do_state(int state)
6121 // always lets the do_state_common() function determine if the state should be skipped
6122 Game_do_state_should_skip = 0;
6124 // legal to set the should skip state anywhere in this function
6125 game_do_state_common(state); // do stuff that may need to be done regardless of state
6127 if(Game_do_state_should_skip){
6132 case GS_STATE_MAIN_MENU:
6133 game_set_frametime(GS_STATE_MAIN_MENU);
6134 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6137 main_hall_do(flFrametime);
6141 case GS_STATE_OPTIONS_MENU:
6142 game_set_frametime(GS_STATE_OPTIONS_MENU);
6143 options_menu_do_frame(flFrametime);
6146 case GS_STATE_BARRACKS_MENU:
6147 game_set_frametime(GS_STATE_BARRACKS_MENU);
6148 barracks_do_frame(flFrametime);
6151 case GS_STATE_TRAINING_MENU:
6152 game_set_frametime(GS_STATE_TRAINING_MENU);
6153 training_menu_do_frame(flFrametime);
6156 case GS_STATE_TECH_MENU:
6157 game_set_frametime(GS_STATE_TECH_MENU);
6158 techroom_do_frame(flFrametime);
6161 case GS_STATE_GAMEPLAY_HELP:
6162 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6163 gameplay_help_do_frame(flFrametime);
6166 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6170 case GS_STATE_GAME_PAUSED:
6174 case GS_STATE_DEBUG_PAUSED:
6176 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6181 case GS_STATE_TRAINING_PAUSED:
6182 game_training_pause_do();
6185 case GS_STATE_LOAD_MISSION_MENU:
6186 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6187 mission_load_menu_do();
6190 case GS_STATE_BRIEFING:
6191 game_set_frametime(GS_STATE_BRIEFING);
6192 brief_do_frame(flFrametime);
6195 case GS_STATE_DEBRIEF:
6196 game_set_frametime(GS_STATE_DEBRIEF);
6197 debrief_do_frame(flFrametime);
6200 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6201 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6202 multi_df_debrief_do();
6205 case GS_STATE_SHIP_SELECT:
6206 game_set_frametime(GS_STATE_SHIP_SELECT);
6207 ship_select_do(flFrametime);
6210 case GS_STATE_WEAPON_SELECT:
6211 game_set_frametime(GS_STATE_WEAPON_SELECT);
6212 weapon_select_do(flFrametime);
6215 case GS_STATE_MISSION_LOG_SCROLLBACK:
6216 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6217 hud_scrollback_do_frame(flFrametime);
6220 case GS_STATE_HUD_CONFIG:
6221 game_set_frametime(GS_STATE_HUD_CONFIG);
6222 hud_config_do_frame(flFrametime);
6225 case GS_STATE_MULTI_JOIN_GAME:
6226 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6227 multi_join_game_do_frame();
6230 case GS_STATE_MULTI_HOST_SETUP:
6231 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6232 multi_create_game_do();
6235 case GS_STATE_MULTI_CLIENT_SETUP:
6236 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6237 multi_game_client_setup_do_frame();
6240 case GS_STATE_CONTROL_CONFIG:
6241 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6242 control_config_do_frame(flFrametime);
6245 case GS_STATE_DEATH_DIED:
6249 case GS_STATE_DEATH_BLEW_UP:
6253 case GS_STATE_SIMULATOR_ROOM:
6254 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6255 sim_room_do_frame(flFrametime);
6258 case GS_STATE_CAMPAIGN_ROOM:
6259 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6260 campaign_room_do_frame(flFrametime);
6263 case GS_STATE_RED_ALERT:
6264 game_set_frametime(GS_STATE_RED_ALERT);
6265 red_alert_do_frame(flFrametime);
6268 case GS_STATE_CMD_BRIEF:
6269 game_set_frametime(GS_STATE_CMD_BRIEF);
6270 cmd_brief_do_frame(flFrametime);
6273 case GS_STATE_CREDITS:
6274 game_set_frametime(GS_STATE_CREDITS);
6275 credits_do_frame(flFrametime);
6278 case GS_STATE_VIEW_MEDALS:
6279 game_set_frametime(GS_STATE_VIEW_MEDALS);
6283 case GS_STATE_SHOW_GOALS:
6284 game_set_frametime(GS_STATE_SHOW_GOALS);
6285 mission_show_goals_do_frame(flFrametime);
6288 case GS_STATE_HOTKEY_SCREEN:
6289 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6290 mission_hotkey_do_frame(flFrametime);
6293 case GS_STATE_VIEW_CUTSCENES:
6294 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6295 cutscenes_screen_do_frame();
6298 case GS_STATE_MULTI_STD_WAIT:
6299 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6300 multi_standalone_wait_do();
6303 case GS_STATE_STANDALONE_MAIN:
6304 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6305 standalone_main_do();
6308 case GS_STATE_MULTI_PAUSED:
6309 game_set_frametime(GS_STATE_MULTI_PAUSED);
6313 case GS_STATE_TEAM_SELECT:
6314 game_set_frametime(GS_STATE_TEAM_SELECT);
6318 case GS_STATE_INGAME_PRE_JOIN:
6319 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6320 multi_ingame_select_do();
6323 case GS_STATE_EVENT_DEBUG:
6325 game_set_frametime(GS_STATE_EVENT_DEBUG);
6326 game_show_event_debug(flFrametime);
6330 case GS_STATE_STANDALONE_POSTGAME:
6331 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6332 multi_standalone_postgame_do();
6335 case GS_STATE_INITIAL_PLAYER_SELECT:
6336 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6340 case GS_STATE_MULTI_MISSION_SYNC:
6341 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6345 case GS_STATE_MULTI_START_GAME:
6346 game_set_frametime(GS_STATE_MULTI_START_GAME);
6347 multi_start_game_do();
6350 case GS_STATE_MULTI_HOST_OPTIONS:
6351 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6352 multi_host_options_do();
6355 case GS_STATE_END_OF_CAMPAIGN:
6356 mission_campaign_end_do();
6359 case GS_STATE_END_DEMO:
6360 game_set_frametime(GS_STATE_END_DEMO);
6361 end_demo_campaign_do();
6364 case GS_STATE_LOOP_BRIEF:
6365 game_set_frametime(GS_STATE_LOOP_BRIEF);
6369 } // end switch(gs_current_state)
6373 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6374 int game_do_ram_check(int ram_in_bytes)
6376 if ( ram_in_bytes < 30*1024*1024 ) {
6377 int allowed_to_run = 1;
6378 if ( ram_in_bytes < 25*1024*1024 ) {
6383 int Freespace_total_ram_MB;
6384 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6386 if ( allowed_to_run ) {
6388 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);
6391 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6392 if ( msgbox_rval == IDCANCEL ) {
6397 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);
6398 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6406 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6407 // If so, copy it over and remove the update directory.
6408 void game_maybe_update_launcher(char *exe_dir)
6410 char src_filename[MAX_PATH];
6411 char dest_filename[MAX_PATH];
6413 strcpy(src_filename, exe_dir);
6414 strcat(src_filename, NOX("\\update\\freespace.exe"));
6416 strcpy(dest_filename, exe_dir);
6417 strcat(dest_filename, NOX("\\freespace.exe"));
6419 // see if src_filename exists
6421 fp = fopen(src_filename, "rb");
6427 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6429 // copy updated freespace.exe to freespace exe dir
6430 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6431 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 );
6435 // delete the file in the update directory
6436 DeleteFile(src_filename);
6438 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6439 char update_dir[MAX_PATH];
6440 strcpy(update_dir, exe_dir);
6441 strcat(update_dir, NOX("\\update"));
6442 RemoveDirectory(update_dir);
6445 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6449 int sub_total_destroyed = 0;
6453 // get the total for all his children
6454 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6455 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6458 // find the # of faces for this _individual_ object
6459 total = submodel_get_num_polys(model_num, sm);
6460 if(strstr(pm->submodel[sm].name, "-destroyed")){
6461 sub_total_destroyed = total;
6465 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6468 *out_total += total + sub_total;
6469 *out_destroyed_total += sub_total_destroyed;
6472 #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);
6473 void game_spew_pof_info()
6475 char *pof_list[1000];
6478 int idx, model_num, i, j;
6480 int total, root_total, model_total, destroyed_total, counted;
6484 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6486 // spew info on all the pofs
6492 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6497 for(idx=0; idx<num_files; idx++, counted++){
6498 sprintf(str, "%s.pof", pof_list[idx]);
6499 model_num = model_load(str, 0, NULL);
6501 pm = model_get(model_num);
6503 // if we have a real model
6508 // go through and print all raw submodels
6509 cfputs("RAW\n", out);
6512 for (i=0; i<pm->n_models; i++) {
6513 total = submodel_get_num_polys(model_num, i);
6515 model_total += total;
6516 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6519 sprintf(str, "Model total %d\n", model_total);
6522 // now go through and do it by LOD
6523 cfputs("BY LOD\n\n", out);
6524 for(i=0; i<pm->n_detail_levels; i++){
6525 sprintf(str, "LOD %d\n", i);
6529 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6531 destroyed_total = 0;
6532 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6533 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6536 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6539 sprintf(str, "TOTAL: %d\n", total + root_total);
6541 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6543 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6546 cfputs("------------------------------------------------------------------------\n\n", out);
6550 if(counted >= MAX_POLYGON_MODELS - 5){
6563 game_spew_pof_info();
6566 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6570 // Don't let more than one instance of Freespace run.
6571 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6573 SetForegroundWindow(hwnd);
6577 // Find out how much RAM is on this machine
6579 ms.dwLength = sizeof(MEMORYSTATUS);
6580 GlobalMemoryStatus(&ms);
6581 Freespace_total_ram = ms.dwTotalPhys;
6583 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6587 if ( ms.dwTotalVirtual < 1024 ) {
6588 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6592 if (!vm_init(24*1024*1024)) {
6593 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 );
6597 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6599 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);
6606 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6607 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6608 seem worth bothering with.
6612 lResult = RegOpenKeyEx(
6613 HKEY_LOCAL_MACHINE, // Where it is
6614 "Software\\Microsoft\\DirectX", // name of key
6615 NULL, // DWORD reserved
6616 KEY_QUERY_VALUE, // Allows all changes
6617 &hKey // Location to store key
6620 if (lResult == ERROR_SUCCESS) {
6622 DWORD dwType, dwLen;
6625 lResult = RegQueryValueEx(
6626 hKey, // Handle to key
6627 "Version", // The values name
6628 NULL, // DWORD reserved
6629 &dwType, // What kind it is
6630 (ubyte *) version, // value to set
6631 &dwLen // How many bytes to set
6634 if (lResult == ERROR_SUCCESS) {
6635 dx_version = atoi(strstr(version, ".") + 1);
6639 DWORD dwType, dwLen;
6642 lResult = RegQueryValueEx(
6643 hKey, // Handle to key
6644 "InstalledVersion", // The values name
6645 NULL, // DWORD reserved
6646 &dwType, // What kind it is
6647 (ubyte *) &val, // value to set
6648 &dwLen // How many bytes to set
6651 if (lResult == ERROR_SUCCESS) {
6659 if (dx_version < 3) {
6660 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6661 "latest version of DirectX at:\n\n"
6662 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6664 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6665 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6670 //=====================================================
6671 // Make sure we're running in the right directory.
6674 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6675 char *p = exe_dir + strlen(exe_dir);
6677 // chop off the filename
6678 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6684 if ( strlen(exe_dir) > 0 ) {
6685 SetCurrentDirectory(exe_dir);
6688 // check for updated freespace.exe
6689 game_maybe_update_launcher(exe_dir);
6695 extern void windebug_memwatch_init();
6696 windebug_memwatch_init();
6700 parse_cmdline(szCmdLine);
6702 #ifdef STANDALONE_ONLY_BUILD
6704 nprintf(("Network", "Standalone running"));
6707 nprintf(("Network", "Standalone running"));
6715 // maybe spew pof stuff
6716 if(Cmdline_spew_pof_info){
6717 game_spew_pof_info();
6722 // non-demo, non-standalone, play the intro movie
6727 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) ){
6729 #if defined(OEM_BUILD)
6730 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6732 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6733 #endif // defined(OEM_BUILD)
6738 if ( !Is_standalone ) {
6740 // release -- movies always play
6743 // 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
6745 // movie_play( NOX("intro.mve"), 0 );
6747 // debug version, movie will only play with -showmovies
6748 #else if !defined(NDEBUG)
6751 // movie_play( NOX("intro.mve"), 0);
6754 if ( Cmdline_show_movies )
6755 movie_play( NOX("intro.mve"), 0 );
6764 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6766 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6770 // only important for non THREADED mode
6773 state = gameseq_process_events();
6774 if ( state == GS_STATE_QUIT_GAME ){
6781 demo_upsell_show_screens();
6783 #elif defined(OEM_BUILD)
6784 // show upsell screens on exit
6785 oem_upsell_show_screens();
6792 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6798 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6800 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6802 // Do nothing here - RecordExceptionInfo() has already done
6803 // everything that is needed. Actually this code won't even
6804 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6805 // the __except clause.
6810 // launcher the fslauncher program on exit
6811 void game_launch_launcher_on_exit()
6814 PROCESS_INFORMATION pi;
6815 char cmd_line[2048];
6816 char original_path[1024] = "";
6818 memset( &si, 0, sizeof(STARTUPINFO) );
6822 _getcwd(original_path, 1023);
6824 // set up command line
6825 strcpy(cmd_line, original_path);
6826 strcat(cmd_line, "\\");
6827 strcat(cmd_line, LAUNCHER_FNAME);
6828 strcat(cmd_line, " -straight_to_update");
6830 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6831 cmd_line, // pointer to command line string
6832 NULL, // pointer to process security attributes
6833 NULL, // pointer to thread security attributes
6834 FALSE, // handle inheritance flag
6835 CREATE_DEFAULT_ERROR_MODE, // creation flags
6836 NULL, // pointer to new environment block
6837 NULL, // pointer to current directory name
6838 &si, // pointer to STARTUPINFO
6839 &pi // pointer to PROCESS_INFORMATION
6841 // to eliminate build warnings
6848 // This function is called when FreeSpace terminates normally.
6850 void game_shutdown(void)
6854 // don't ever flip a page on the standalone!
6855 if(!(Game_mode & GM_STANDALONE_SERVER)){
6861 // if the player has left the "player select" screen and quit the game without actually choosing
6862 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6863 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6867 // load up common multiplayer icons
6868 multi_unload_common_icons();
6870 shockwave_close(); // release any memory used by shockwave system
6871 fireball_close(); // free fireball system
6872 ship_close(); // free any memory that was allocated for the ships
6873 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6874 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6875 bm_unload_all(); // free bitmaps
6876 mission_campaign_close(); // close out the campaign stuff
6877 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6879 #ifdef MULTI_USE_LAG
6883 // the menu close functions will unload the bitmaps if they were displayed during the game
6884 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6887 training_menu_close();
6890 extern void joy_close();
6893 audiostream_close();
6895 event_music_close();
6899 // HACKITY HACK HACK
6900 // if this flag is set, we should be firing up the launcher when exiting freespace
6901 extern int Multi_update_fireup_launcher_on_exit;
6902 if(Multi_update_fireup_launcher_on_exit){
6903 game_launch_launcher_on_exit();
6907 // game_stop_looped_sounds()
6909 // This function will call the appropriate stop looped sound functions for those
6910 // modules which use looping sounds. It is not enough just to stop a looping sound
6911 // at the DirectSound level, the game is keeping track of looping sounds, and this
6912 // function is used to inform the game that looping sounds are being halted.
6914 void game_stop_looped_sounds()
6916 hud_stop_looped_locking_sounds();
6917 hud_stop_looped_engine_sounds();
6918 afterburner_stop_sounds();
6919 player_stop_looped_sounds();
6920 obj_snd_stop_all(); // stop all object-linked persistant sounds
6921 game_stop_subspace_ambient_sound();
6922 snd_stop(Radar_static_looping);
6923 Radar_static_looping = -1;
6924 snd_stop(Target_static_looping);
6925 shipfx_stop_engine_wash_sound();
6926 Target_static_looping = -1;
6929 //////////////////////////////////////////////////////////////////////////
6931 // Code for supporting an animating mouse pointer
6934 //////////////////////////////////////////////////////////////////////////
6936 typedef struct animating_obj
6945 static animating_obj Animating_mouse;
6947 // ----------------------------------------------------------------------------
6948 // init_animating_pointer()
6950 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6951 // gets properly initialized
6953 void init_animating_pointer()
6955 Animating_mouse.first_frame = -1;
6956 Animating_mouse.num_frames = 0;
6957 Animating_mouse.current_frame = -1;
6958 Animating_mouse.time = 0.0f;
6959 Animating_mouse.elapsed_time = 0.0f;
6962 // ----------------------------------------------------------------------------
6963 // load_animating_pointer()
6965 // Called at game init to load in the frames for the animating mouse pointer
6967 // input: filename => filename of animation file that holds the animation
6969 void load_animating_pointer(char *filename, int dx, int dy)
6974 init_animating_pointer();
6976 am = &Animating_mouse;
6977 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
6978 if ( am->first_frame == -1 )
6979 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
6980 am->current_frame = 0;
6981 am->time = am->num_frames / i2fl(fps);
6984 // ----------------------------------------------------------------------------
6985 // unload_animating_pointer()
6987 // Called at game shutdown to free the memory used to store the animation frames
6989 void unload_animating_pointer()
6994 am = &Animating_mouse;
6995 for ( i = 0; i < am->num_frames; i++ ) {
6996 Assert( (am->first_frame+i) >= 0 );
6997 bm_release(am->first_frame + i);
7000 am->first_frame = -1;
7002 am->current_frame = -1;
7005 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7006 void game_render_mouse(float frametime)
7011 // if animating cursor exists, play the next frame
7012 am = &Animating_mouse;
7013 if ( am->first_frame != -1 ) {
7014 mouse_get_pos(&mx, &my);
7015 am->elapsed_time += frametime;
7016 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7017 if ( am->current_frame >= am->num_frames ) {
7018 am->current_frame = 0;
7019 am->elapsed_time = 0.0f;
7021 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7025 // ----------------------------------------------------------------------------
7026 // game_maybe_draw_mouse()
7028 // determines whether to draw the mouse pointer at all, and what frame of
7029 // animation to use if the mouse is animating
7031 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7033 // input: frametime => elapsed frame time in seconds since last call
7035 void game_maybe_draw_mouse(float frametime)
7039 game_state = gameseq_get_state();
7041 switch ( game_state ) {
7042 case GS_STATE_GAME_PAUSED:
7043 // case GS_STATE_MULTI_PAUSED:
7044 case GS_STATE_GAME_PLAY:
7045 case GS_STATE_DEATH_DIED:
7046 case GS_STATE_DEATH_BLEW_UP:
7047 if ( popup_active() || popupdead_is_active() ) {
7059 if ( !Mouse_hidden )
7060 game_render_mouse(frametime);
7064 void game_do_training_checks()
7068 waypoint_list *wplp;
7070 if (Training_context & TRAINING_CONTEXT_SPEED) {
7071 s = (int) Player_obj->phys_info.fspeed;
7072 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7073 if (!Training_context_speed_set) {
7074 Training_context_speed_set = 1;
7075 Training_context_speed_timestamp = timestamp();
7079 Training_context_speed_set = 0;
7082 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7083 wplp = &Waypoint_lists[Training_context_path];
7084 if (wplp->count > Training_context_goal_waypoint) {
7085 i = Training_context_goal_waypoint;
7087 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7088 if (d <= Training_context_distance) {
7089 Training_context_at_waypoint = i;
7090 if (Training_context_goal_waypoint == i) {
7091 Training_context_goal_waypoint++;
7092 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7099 if (i == wplp->count)
7102 } while (i != Training_context_goal_waypoint);
7106 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7107 Players_target = Player_ai->target_objnum;
7108 Players_targeted_subsys = Player_ai->targeted_subsys;
7109 Players_target_timestamp = timestamp();
7113 /////////// Following is for event debug view screen
7117 #define EVENT_DEBUG_MAX 5000
7118 #define EVENT_DEBUG_EVENT 0x8000
7120 int Event_debug_index[EVENT_DEBUG_MAX];
7123 void game_add_event_debug_index(int n, int indent)
7125 if (ED_count < EVENT_DEBUG_MAX)
7126 Event_debug_index[ED_count++] = n | (indent << 16);
7129 void game_add_event_debug_sexp(int n, int indent)
7134 if (Sexp_nodes[n].first >= 0) {
7135 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7136 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7140 game_add_event_debug_index(n, indent);
7141 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7142 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7144 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7147 void game_event_debug_init()
7152 for (e=0; e<Num_mission_events; e++) {
7153 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7154 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7158 void game_show_event_debug(float frametime)
7162 int font_height, font_width;
7164 static int scroll_offset = 0;
7166 k = game_check_key();
7172 if (scroll_offset < 0)
7182 scroll_offset -= 20;
7183 if (scroll_offset < 0)
7188 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7192 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7198 gr_set_color_fast(&Color_bright);
7200 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7202 gr_set_color_fast(&Color_normal);
7204 gr_get_string_size(&font_width, &font_height, NOX("test"));
7205 y_max = gr_screen.max_h - font_height - 5;
7209 while (k < ED_count) {
7210 if (y_index > y_max)
7213 z = Event_debug_index[k];
7214 if (z & EVENT_DEBUG_EVENT) {
7216 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7217 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7218 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7219 Mission_events[z].repeat_count, Mission_events[z].interval);
7227 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7228 switch (Sexp_nodes[z & 0x7fff].value) {
7230 strcat(buf, NOX(" (True)"));
7234 strcat(buf, NOX(" (False)"));
7237 case SEXP_KNOWN_TRUE:
7238 strcat(buf, NOX(" (Always true)"));
7241 case SEXP_KNOWN_FALSE:
7242 strcat(buf, NOX(" (Always false)"));
7245 case SEXP_CANT_EVAL:
7246 strcat(buf, NOX(" (Can't eval)"));
7250 case SEXP_NAN_FOREVER:
7251 strcat(buf, NOX(" (Not a number)"));
7256 gr_printf(10, y_index, buf);
7257 y_index += font_height;
7270 extern int Tmap_npixels;
7272 int Tmap_num_too_big = 0;
7273 int Num_models_needing_splitting = 0;
7275 void Time_model( int modelnum )
7277 // mprintf(( "Timing ship '%s'\n", si->name ));
7279 vector eye_pos, model_pos;
7280 matrix eye_orient, model_orient;
7282 polymodel *pm = model_get( modelnum );
7284 int l = strlen(pm->filename);
7286 if ( (l == '/') || (l=='\\') || (l==':')) {
7292 char *pof_file = &pm->filename[l];
7294 int model_needs_splitting = 0;
7296 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7298 for (i=0; i<pm->n_textures; i++ ) {
7299 char filename[1024];
7302 int bmp_num = pm->original_textures[i];
7303 if ( bmp_num > -1 ) {
7304 bm_get_palette(pm->original_textures[i], pal, filename );
7306 bm_get_info( pm->original_textures[i],&w, &h );
7309 if ( (w > 512) || (h > 512) ) {
7310 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7312 model_needs_splitting++;
7315 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7319 if ( model_needs_splitting ) {
7320 Num_models_needing_splitting++;
7322 eye_orient = model_orient = vmd_identity_matrix;
7323 eye_pos = model_pos = vmd_zero_vector;
7325 eye_pos.z = -pm->rad*2.0f;
7327 vector eye_to_model;
7329 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7330 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7332 fix t1 = timer_get_fixed_seconds();
7335 ta.p = ta.b = ta.h = 0.0f;
7340 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7342 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7344 modelstats_num_polys = modelstats_num_verts = 0;
7346 while( ta.h < PI2 ) {
7349 vm_angles_2_matrix(&m1, &ta );
7350 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7357 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7359 model_clear_instance( modelnum );
7360 model_set_detail_level(0); // use highest detail level
7361 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7369 int k = key_inkey();
7370 if ( k == KEY_ESC ) {
7375 fix t2 = timer_get_fixed_seconds();
7377 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7378 //bitmaps_used_this_frame /= framecount;
7380 modelstats_num_polys /= framecount;
7381 modelstats_num_verts /= framecount;
7383 Tmap_npixels /=framecount;
7386 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7387 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 );
7388 // 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 );
7394 int Time_models = 0;
7395 DCF_BOOL( time_models, Time_models );
7397 void Do_model_timings_test()
7401 if ( !Time_models ) return;
7403 mprintf(( "Timing models!\n" ));
7407 ubyte model_used[MAX_POLYGON_MODELS];
7408 int model_id[MAX_POLYGON_MODELS];
7409 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7414 for (i=0; i<Num_ship_types; i++ ) {
7415 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7417 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7418 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7421 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7422 if ( !Texture_fp ) return;
7424 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7425 if ( !Time_fp ) return;
7427 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7428 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7430 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7431 if ( model_used[i] ) {
7432 Time_model( model_id[i] );
7436 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7437 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7446 // Call this function when you want to inform the player that a feature is not
7447 // enabled in the DEMO version of FreSpace
7448 void game_feature_not_in_demo_popup()
7450 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7453 // format the specified time (fixed point) into a nice string
7454 void game_format_time(fix m_time,char *time_str)
7457 int hours,minutes,seconds;
7460 mtime = f2fl(m_time);
7462 // get the hours, minutes and seconds
7463 hours = (int)(mtime / 3600.0f);
7465 mtime -= (3600.0f * (float)hours);
7467 seconds = (int)mtime%60;
7468 minutes = (int)mtime/60;
7470 // print the hour if necessary
7472 sprintf(time_str,XSTR( "%d:", 201),hours);
7473 // if there are less than 10 minutes, print a leading 0
7475 strcpy(tmp,NOX("0"));
7476 strcat(time_str,tmp);
7480 // print the minutes
7482 sprintf(tmp,XSTR( "%d:", 201),minutes);
7483 strcat(time_str,tmp);
7485 sprintf(time_str,XSTR( "%d:", 201),minutes);
7488 // print the seconds
7490 strcpy(tmp,NOX("0"));
7491 strcat(time_str,tmp);
7493 sprintf(tmp,"%d",seconds);
7494 strcat(time_str,tmp);
7497 // Stuff version string in *str.
7498 void get_version_string(char *str)
7501 if ( FS_VERSION_BUILD == 0 ) {
7502 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7504 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7507 #if defined (FS2_DEMO)
7509 #elif defined (OEM_BUILD)
7510 strcat(str, " (OEM)");
7516 char myname[_MAX_PATH];
7517 int namelen, major, minor, build, waste;
7518 unsigned int buf_size;
7524 // Find my EXE file name
7525 hMod = GetModuleHandle(NULL);
7526 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7528 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7529 infop = (char *)malloc(version_size);
7530 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7532 // get the product version
7533 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7534 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7536 sprintf(str,"Dv%d.%02d",major, minor);
7538 sprintf(str,"v%d.%02d",major, minor);
7543 void get_version_string_short(char *str)
7545 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7548 // ----------------------------------------------------------------
7550 // OEM UPSELL SCREENS BEGIN
7552 // ----------------------------------------------------------------
7553 #if defined(OEM_BUILD)
7555 #define NUM_OEM_UPSELL_SCREENS 3
7556 #define OEM_UPSELL_SCREEN_DELAY 10000
7558 static int Oem_upsell_bitmaps_loaded = 0;
7559 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7560 static int Oem_upsell_screen_number = 0;
7561 static int Oem_upsell_show_next_bitmap_time;
7564 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7577 static int Oem_normal_cursor = -1;
7578 static int Oem_web_cursor = -1;
7579 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7580 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7582 void oem_upsell_next_screen()
7584 Oem_upsell_screen_number++;
7585 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7586 // extra long delay, mouse shown on last upsell
7587 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7591 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7595 void oem_upsell_load_bitmaps()
7599 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7600 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7604 void oem_upsell_unload_bitmaps()
7608 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7609 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7610 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7615 Oem_upsell_bitmaps_loaded = 0;
7618 // clickable hotspot on 3rd OEM upsell screen
7619 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7621 28, 350, 287, 96 // x, y, w, h
7624 45, 561, 460, 152 // x, y, w, h
7628 void oem_upsell_show_screens()
7630 int current_time, k;
7633 if ( !Oem_upsell_bitmaps_loaded ) {
7634 oem_upsell_load_bitmaps();
7635 Oem_upsell_bitmaps_loaded = 1;
7638 // may use upsell screens more than once
7639 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7640 Oem_upsell_screen_number = 0;
7646 int nframes; // used to pass, not really needed (should be 1)
7647 Oem_normal_cursor = gr_get_cursor_bitmap();
7648 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7649 Assert(Oem_web_cursor >= 0);
7650 if (Oem_web_cursor < 0) {
7651 Oem_web_cursor = Oem_normal_cursor;
7656 //oem_reset_trailer_timer();
7658 current_time = timer_get_milliseconds();
7663 // advance screen on keypress or timeout
7664 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7665 oem_upsell_next_screen();
7668 // check if we are done
7669 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7670 Oem_upsell_screen_number--;
7673 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7678 // show me the upsell
7679 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7680 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7684 // if this is the 3rd upsell, make it clickable, d00d
7685 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7687 int button_state = mouse_get_pos(&mx, &my);
7688 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])
7689 && (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]) )
7692 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7695 if (button_state & MOUSE_LEFT_BUTTON) {
7697 multi_pxo_url(OEM_UPSELL_URL);
7701 // switch cursor back to normal one
7702 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7707 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7717 oem_upsell_unload_bitmaps();
7719 // switch cursor back to normal one
7720 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7724 #endif // defined(OEM_BUILD)
7725 // ----------------------------------------------------------------
7727 // OEM UPSELL SCREENS END
7729 // ----------------------------------------------------------------
7733 // ----------------------------------------------------------------
7735 // DEMO UPSELL SCREENS BEGIN
7737 // ----------------------------------------------------------------
7741 //#define NUM_DEMO_UPSELL_SCREENS 4
7743 #define NUM_DEMO_UPSELL_SCREENS 2
7744 #define DEMO_UPSELL_SCREEN_DELAY 3000
7746 static int Demo_upsell_bitmaps_loaded = 0;
7747 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7748 static int Demo_upsell_screen_number = 0;
7749 static int Demo_upsell_show_next_bitmap_time;
7752 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7765 void demo_upsell_next_screen()
7767 Demo_upsell_screen_number++;
7768 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7769 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7771 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7775 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7776 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7777 #ifndef HARDWARE_ONLY
7778 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7785 void demo_upsell_load_bitmaps()
7789 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7790 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7794 void demo_upsell_unload_bitmaps()
7798 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7799 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7800 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7805 Demo_upsell_bitmaps_loaded = 0;
7808 void demo_upsell_show_screens()
7810 int current_time, k;
7813 if ( !Demo_upsell_bitmaps_loaded ) {
7814 demo_upsell_load_bitmaps();
7815 Demo_upsell_bitmaps_loaded = 1;
7818 // may use upsell screens more than once
7819 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7820 Demo_upsell_screen_number = 0;
7827 demo_reset_trailer_timer();
7829 current_time = timer_get_milliseconds();
7836 // don't time out, wait for keypress
7838 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7839 demo_upsell_next_screen();
7844 demo_upsell_next_screen();
7847 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7848 Demo_upsell_screen_number--;
7851 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7856 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7857 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7862 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7872 demo_upsell_unload_bitmaps();
7877 // ----------------------------------------------------------------
7879 // DEMO UPSELL SCREENS END
7881 // ----------------------------------------------------------------
7884 // ----------------------------------------------------------------
7886 // Subspace Ambient Sound START
7888 // ----------------------------------------------------------------
7890 static int Subspace_ambient_left_channel = -1;
7891 static int Subspace_ambient_right_channel = -1;
7894 void game_start_subspace_ambient_sound()
7896 if ( Subspace_ambient_left_channel < 0 ) {
7897 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7900 if ( Subspace_ambient_right_channel < 0 ) {
7901 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7905 void game_stop_subspace_ambient_sound()
7907 if ( Subspace_ambient_left_channel >= 0 ) {
7908 snd_stop(Subspace_ambient_left_channel);
7909 Subspace_ambient_left_channel = -1;
7912 if ( Subspace_ambient_right_channel >= 0 ) {
7913 snd_stop(Subspace_ambient_right_channel);
7914 Subspace_ambient_right_channel = -1;
7918 // ----------------------------------------------------------------
7920 // Subspace Ambient Sound END
7922 // ----------------------------------------------------------------
7924 // ----------------------------------------------------------------
7926 // CDROM detection code START
7928 // ----------------------------------------------------------------
7930 #define CD_SIZE_72_MINUTE_MAX (697000000)
7932 uint game_get_cd_used_space(char *path)
7935 char use_path[512] = "";
7936 char sub_path[512] = "";
7937 WIN32_FIND_DATA find;
7940 // recurse through all files and directories
7941 strcpy(use_path, path);
7942 strcat(use_path, "*.*");
7943 find_handle = FindFirstFile(use_path, &find);
7946 if(find_handle == INVALID_HANDLE_VALUE){
7952 // subdirectory. make sure to ignore . and ..
7953 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
7955 strcpy(sub_path, path);
7956 strcat(sub_path, find.cFileName);
7957 strcat(sub_path, "\\");
7958 total += game_get_cd_used_space(sub_path);
7960 total += (uint)find.nFileSizeLow;
7962 } while(FindNextFile(find_handle, &find));
7965 FindClose(find_handle);
7972 // if volume_name is non-null, the CD name must match that
7973 int find_freespace_cd(char *volume_name)
7975 char oldpath[MAX_PATH];
7979 int volume_match = 0;
7983 GetCurrentDirectory(MAX_PATH, oldpath);
7985 for (i = 0; i < 26; i++)
7991 path[0] = (char)('A'+i);
7992 if (GetDriveType(path) == DRIVE_CDROM) {
7994 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
7995 nprintf(("CD", "CD volume: %s\n", volume));
7997 // check for any CD volume
7998 int volume1_present = 0;
7999 int volume2_present = 0;
8000 int volume3_present = 0;
8002 char full_check[512] = "";
8004 // look for setup.exe
8005 strcpy(full_check, path);
8006 strcat(full_check, "setup.exe");
8007 find_handle = _findfirst(full_check, &find);
8008 if(find_handle != -1){
8009 volume1_present = 1;
8010 _findclose(find_handle);
8013 // look for intro.mve
8014 strcpy(full_check, path);
8015 strcat(full_check, "intro.mve");
8016 find_handle = _findfirst(full_check, &find);
8017 if(find_handle != -1){
8018 volume2_present = 1;
8019 _findclose(find_handle);
8022 // look for endpart1.mve
8023 strcpy(full_check, path);
8024 strcat(full_check, "endpart1.mve");
8025 find_handle = _findfirst(full_check, &find);
8026 if(find_handle != -1){
8027 volume3_present = 1;
8028 _findclose(find_handle);
8031 // see if we have the specific CD we're looking for
8032 if ( volume_name ) {
8034 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8038 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8042 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8046 if ( volume1_present || volume2_present || volume3_present ) {
8051 // 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
8052 if ( volume_match ){
8054 // 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
8055 if(volume2_present || volume3_present) {
8056 // first step - check to make sure its a cdrom
8057 if(GetDriveType(path) != DRIVE_CDROM){
8061 #if !defined(OEM_BUILD)
8062 // oem not on 80 min cds, so dont check tha size
8064 uint used_space = game_get_cd_used_space(path);
8065 if(used_space < CD_SIZE_72_MINUTE_MAX){
8068 #endif // !defined(OEM_BUILD)
8076 #endif // RELEASE_REAL
8082 SetCurrentDirectory(oldpath);
8086 int set_cdrom_path(int drive_num)
8090 if (drive_num < 0) { //no CD
8092 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8095 strcpy(Game_CDROM_dir,""); //set directory
8099 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8115 i = find_freespace_cd();
8117 rval = set_cdrom_path(i);
8121 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8123 nprintf(("CD", "FreeSpace CD not found\n"));
8131 int Last_cd_label_found = 0;
8132 char Last_cd_label[256];
8134 int game_cd_changed()
8140 if ( strlen(Game_CDROM_dir) == 0 ) {
8144 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8146 if ( found != Last_cd_label_found ) {
8147 Last_cd_label_found = found;
8149 mprintf(( "CD '%s' was inserted\n", label ));
8152 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8156 if ( Last_cd_label_found ) {
8157 if ( !stricmp( Last_cd_label, label )) {
8158 //mprintf(( "CD didn't change\n" ));
8160 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8164 // none found before, none found now.
8165 //mprintf(( "still no CD...\n" ));
8169 Last_cd_label_found = found;
8171 strcpy( Last_cd_label, label );
8173 strcpy( Last_cd_label, "" );
8179 // check if _any_ FreeSpace2 CDs are in the drive
8180 // return: 1 => CD now in drive
8181 // 0 => Could not find CD, they refuse to put it in the drive
8182 int game_do_cd_check(char *volume_name)
8184 #if !defined(GAME_CD_CHECK)
8190 int num_attempts = 0;
8191 int refresh_files = 0;
8193 int path_set_ok, popup_rval;
8195 cd_drive_num = find_freespace_cd(volume_name);
8196 path_set_ok = set_cdrom_path(cd_drive_num);
8197 if ( path_set_ok ) {
8199 if ( refresh_files ) {
8211 // no CD found, so prompt user
8212 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8214 if ( popup_rval != 1 ) {
8219 if ( num_attempts++ > 5 ) {
8230 // check if _any_ FreeSpace2 CDs are in the drive
8231 // return: 1 => CD now in drive
8232 // 0 => Could not find CD, they refuse to put it in the drive
8233 int game_do_cd_check_specific(char *volume_name, int cdnum)
8238 int num_attempts = 0;
8239 int refresh_files = 0;
8241 int path_set_ok, popup_rval;
8243 cd_drive_num = find_freespace_cd(volume_name);
8244 path_set_ok = set_cdrom_path(cd_drive_num);
8245 if ( path_set_ok ) {
8247 if ( refresh_files ) {
8258 // no CD found, so prompt user
8259 #if defined(DVD_MESSAGE_HACK)
8260 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8262 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8265 if ( popup_rval != 1 ) {
8270 if ( num_attempts++ > 5 ) {
8280 // only need to do this in RELEASE_REAL
8281 int game_do_cd_mission_check(char *filename)
8287 fs_builtin_mission *m = game_find_builtin_mission(filename);
8289 // check for changed CD
8290 if(game_cd_changed()){
8295 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8299 // not builtin, so do a general check (any FS2 CD will do)
8301 return game_do_cd_check();
8304 // does not have any CD requirement, do a general check
8305 if(strlen(m->cd_volume) <= 0){
8306 return game_do_cd_check();
8310 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8312 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8314 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8317 return game_do_cd_check();
8320 // did we find the cd?
8321 if(find_freespace_cd(m->cd_volume) >= 0){
8325 // make sure the volume exists
8326 int num_attempts = 0;
8327 int refresh_files = 0;
8329 int path_set_ok, popup_rval;
8331 cd_drive_num = find_freespace_cd(m->cd_volume);
8332 path_set_ok = set_cdrom_path(cd_drive_num);
8333 if ( path_set_ok ) {
8335 if ( refresh_files ) {
8342 // no CD found, so prompt user
8343 #if defined(DVD_MESSAGE_HACK)
8344 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8346 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8350 if ( popup_rval != 1 ) {
8355 if ( num_attempts++ > 5 ) {
8367 // ----------------------------------------------------------------
8369 // CDROM detection code END
8371 // ----------------------------------------------------------------
8373 // ----------------------------------------------------------------
8374 // SHIPS TBL VERIFICATION STUFF
8377 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8378 #define NUM_SHIPS_TBL_CHECKSUMS 1
8380 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8381 -463907578, // US - beta 1
8382 1696074201, // FS2 demo
8385 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8386 // -1022810006, // 1.0 FULL
8387 -1254285366 // 1.2 FULL (German)
8390 void verify_ships_tbl()
8394 Game_ships_tbl_valid = 1;
8400 // detect if the packfile exists
8401 CFILE *detect = cfopen("ships.tbl", "rb");
8402 Game_ships_tbl_valid = 0;
8406 Game_ships_tbl_valid = 0;
8410 // get the long checksum of the file
8412 cfseek(detect, 0, SEEK_SET);
8413 cf_chksum_long(detect, &file_checksum);
8417 // now compare the checksum/filesize against known #'s
8418 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8419 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8420 Game_ships_tbl_valid = 1;
8427 DCF(shipspew, "display the checksum for the current ships.tbl")
8430 CFILE *detect = cfopen("ships.tbl", "rb");
8431 // get the long checksum of the file
8433 cfseek(detect, 0, SEEK_SET);
8434 cf_chksum_long(detect, &file_checksum);
8437 dc_printf("%d", file_checksum);
8440 // ----------------------------------------------------------------
8441 // WEAPONS TBL VERIFICATION STUFF
8444 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8445 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8447 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8448 141718090, // US - beta 1
8449 -266420030, // demo 1
8452 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8453 // 399297860, // 1.0 FULL
8454 -553984927 // 1.2 FULL (german)
8457 void verify_weapons_tbl()
8461 Game_weapons_tbl_valid = 1;
8467 // detect if the packfile exists
8468 CFILE *detect = cfopen("weapons.tbl", "rb");
8469 Game_weapons_tbl_valid = 0;
8473 Game_weapons_tbl_valid = 0;
8477 // get the long checksum of the file
8479 cfseek(detect, 0, SEEK_SET);
8480 cf_chksum_long(detect, &file_checksum);
8484 // now compare the checksum/filesize against known #'s
8485 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8486 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8487 Game_weapons_tbl_valid = 1;
8494 DCF(wepspew, "display the checksum for the current weapons.tbl")
8497 CFILE *detect = cfopen("weapons.tbl", "rb");
8498 // get the long checksum of the file
8500 cfseek(detect, 0, SEEK_SET);
8501 cf_chksum_long(detect, &file_checksum);
8504 dc_printf("%d", file_checksum);
8507 // if the game is running using hacked data
8508 int game_hacked_data()
8511 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8519 void display_title_screen()
8521 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8522 ///int title_bitmap;
8525 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8526 if (title_bitmap == -1) {
8531 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8532 extern void d3d_start_frame();
8537 gr_set_bitmap(title_bitmap);
8543 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8544 extern void d3d_stop_frame();
8551 bm_unload(title_bitmap);
8552 #endif // FS2_DEMO || OEM_BUILD
8555 // return true if the game is running with "low memory", which is less than 48MB
8556 bool game_using_low_mem()
8558 if (Use_low_mem == 0) {