2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 201 6/16/00 3:15p Jefff
15 * sim of the year dvd version changes, a few german soty localization
18 * 200 11/03/99 11:06a Jefff
21 * 199 10/26/99 5:07p Jamest
22 * fixed jeffs dumb debug code
24 * 198 10/25/99 5:53p Jefff
25 * call control_config_common_init() on startup
27 * 197 10/14/99 10:18a Daveb
28 * Fixed incorrect CD checking problem on standalone server.
30 * 196 10/13/99 9:22a Daveb
31 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
32 * related to movies. Fixed launcher spawning from PXO screen.
34 * 195 10/06/99 11:05a Jefff
35 * new oem upsell 3 hotspot coords
37 * 194 10/06/99 10:31a Jefff
40 * 193 10/01/99 9:10a Daveb
43 * 192 9/15/99 4:57a Dave
44 * Updated ships.tbl checksum
46 * 191 9/15/99 3:58a Dave
47 * Removed framerate warning at all times.
49 * 190 9/15/99 3:16a Dave
50 * Remove mt-011.fs2 from the builtin mission list.
52 * 189 9/15/99 1:45a Dave
53 * Don't init joystick on standalone. Fixed campaign mode on standalone.
54 * Fixed no-score-report problem in TvT
56 * 188 9/14/99 6:08a Dave
57 * Updated (final) single, multi, and campaign list.
59 * 187 9/14/99 3:26a Dave
60 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
61 * respawn-too-early problem. Made a few crash points safe.
63 * 186 9/13/99 4:52p Dave
66 * 185 9/12/99 8:09p Dave
67 * Fixed problem where skip-training button would cause mission messages
68 * not to get paged out for the current mission.
70 * 184 9/10/99 11:53a Dave
71 * Shutdown graphics before sound to eliminate apparent lockups when
72 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
74 * 183 9/09/99 11:40p Dave
75 * Handle an Assert() in beam code. Added supernova sounds. Play the right
76 * 2 end movies properly, based upon what the player did in the mission.
78 * 182 9/08/99 10:29p Dave
79 * Make beam sound pausing and unpausing much safer.
81 * 181 9/08/99 10:01p Dave
82 * Make sure game won't run in a drive's root directory. Make sure
83 * standalone routes suqad war messages properly to the host.
85 * 180 9/08/99 3:22p Dave
86 * Updated builtin mission list.
88 * 179 9/08/99 12:01p Jefff
89 * fixed Game_builtin_mission_list typo on Training-2.fs2
91 * 178 9/08/99 9:48a Andsager
92 * Add force feedback for engine wash.
94 * 177 9/07/99 4:01p Dave
95 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
96 * does everything properly (setting up address when binding). Remove
97 * black rectangle background from UI_INPUTBOX.
99 * 176 9/13/99 2:40a Dave
100 * Comment in full 80 minute CD check for RELEASE_REAL builds.
102 * 175 9/06/99 6:38p Dave
103 * Improved CD detection code.
105 * 174 9/06/99 1:30a Dave
106 * Intermediate checkin. Started on enforcing CD-in-drive to play the
109 * 173 9/06/99 1:16a Dave
110 * Make sure the user sees the intro movie.
112 * 172 9/04/99 8:00p Dave
113 * Fixed up 1024 and 32 bit movie support.
115 * 171 9/03/99 1:32a Dave
116 * CD checking by act. Added support to play 2 cutscenes in a row
117 * seamlessly. Fixed super low level cfile bug related to files in the
118 * root directory of a CD. Added cheat code to set campaign mission # in
121 * 170 9/01/99 10:49p Dave
122 * Added nice SquadWar checkbox to the client join wait screen.
124 * 169 9/01/99 10:14a Dave
127 * 168 8/29/99 4:51p Dave
128 * Fixed damaged checkin.
130 * 167 8/29/99 4:18p Andsager
131 * New "burst" limit for friendly damage. Also credit more damage done
132 * against large friendly ships.
134 * 166 8/27/99 6:38p Alanl
135 * crush the blasted repeating messages bug
137 * 164 8/26/99 9:09p Dave
138 * Force framerate check in everything but a RELEASE_REAL build.
140 * 163 8/26/99 9:45a Dave
141 * First pass at easter eggs and cheats.
143 * 162 8/24/99 8:55p Dave
144 * Make sure nondimming pixels work properly in tech menu.
146 * 161 8/24/99 1:49a Dave
147 * Fixed client-side afterburner stuttering. Added checkbox for no version
148 * checking on PXO join. Made button info passing more friendly between
151 * 160 8/22/99 5:53p Dave
152 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
153 * instead of ship designations for multiplayer players.
155 * 159 8/22/99 1:19p Dave
156 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
157 * which d3d cards are detected.
159 * 158 8/20/99 2:09p Dave
160 * PXO banner cycling.
162 * 157 8/19/99 10:59a Dave
163 * Packet loss detection.
165 * 156 8/19/99 10:12a Alanl
166 * preload mission-specific messages on machines greater than 48MB
168 * 155 8/16/99 4:04p Dave
169 * Big honking checkin.
171 * 154 8/11/99 5:54p Dave
172 * Fixed collision problem. Fixed standalone ghost problem.
174 * 153 8/10/99 7:59p Jefff
177 * 152 8/10/99 6:54p Dave
178 * Mad optimizations. Added paging to the nebula effect.
180 * 151 8/10/99 3:44p Jefff
181 * loads Intelligence information on startup
183 * 150 8/09/99 3:47p Dave
184 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
185 * non-nebula missions.
187 * 149 8/09/99 2:21p Andsager
188 * Fix patching from multiplayer direct to launcher update tab.
190 * 148 8/09/99 10:36a Dave
191 * Version info for game.
193 * 147 8/06/99 9:46p Dave
194 * Hopefully final changes for the demo.
196 * 146 8/06/99 3:34p Andsager
197 * Make title version info "(D)" -> "D" show up nicely
199 * 145 8/06/99 2:59p Adamp
200 * Fixed NT launcher/update problem.
202 * 144 8/06/99 1:52p Dave
203 * Bumped up MAX_BITMAPS for the demo.
205 * 143 8/06/99 12:17p Andsager
206 * Demo: down to just 1 demo dog
208 * 142 8/05/99 9:39p Dave
209 * Yet another new checksum.
211 * 141 8/05/99 6:19p Dave
212 * New demo checksums.
214 * 140 8/05/99 5:31p Andsager
215 * Up demo version 1.01
217 * 139 8/05/99 4:22p Andsager
218 * No time limit on upsell screens. Reverse order of display of upsell
221 * 138 8/05/99 4:17p Dave
222 * Tweaks to client interpolation.
224 * 137 8/05/99 3:52p Danw
226 * 136 8/05/99 3:01p Danw
228 * 135 8/05/99 2:43a Anoop
229 * removed duplicate definition.
231 * 134 8/05/99 2:13a Dave
234 * 133 8/05/99 2:05a Dave
237 * 132 8/05/99 1:22a Andsager
240 * 131 8/04/99 9:51p Andsager
241 * Add title screen to demo
243 * 130 8/04/99 6:47p Jefff
244 * fixed link error resulting from #ifdefs
246 * 129 8/04/99 6:26p Dave
247 * Updated ship tbl checksum.
249 * 128 8/04/99 5:40p Andsager
250 * Add multiple demo dogs
252 * 127 8/04/99 5:36p Andsager
253 * Show upsell screens at end of demo campaign before returning to main
256 * 126 8/04/99 11:42a Danw
257 * tone down EAX reverb
259 * 125 8/04/99 11:23a Dave
260 * Updated demo checksums.
262 * 124 8/03/99 11:02p Dave
263 * Maybe fixed sync problems in multiplayer.
265 * 123 8/03/99 6:21p Jefff
268 * 122 8/03/99 3:44p Andsager
269 * Launch laucher if trying to run FS without first having configured
272 * 121 8/03/99 12:45p Dave
275 * 120 8/02/99 9:13p Dave
278 * 119 7/30/99 10:31p Dave
279 * Added comm menu to the configurable hud files.
281 * 118 7/30/99 5:17p Andsager
282 * first fs2demo checksums
284 * 117 7/29/99 3:09p Anoop
286 * 116 7/29/99 12:05a Dave
287 * Nebula speed optimizations.
289 * 115 7/27/99 8:59a Andsager
290 * Make major, minor version consistent for all builds. Only show major
291 * and minor for launcher update window.
293 * 114 7/26/99 5:50p Dave
294 * Revised ingame join. Better? We'll see....
296 * 113 7/26/99 5:27p Andsager
297 * Add training mission as builtin to demo build
299 * 112 7/24/99 1:54p Dave
300 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
303 * 111 7/22/99 4:00p Dave
304 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
306 * 110 7/21/99 8:10p Dave
307 * First run of supernova effect.
309 * 109 7/20/99 1:49p Dave
310 * Peter Drake build. Fixed some release build warnings.
312 * 108 7/19/99 2:26p Andsager
313 * set demo multiplayer missions
315 * 107 7/18/99 5:19p Dave
316 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
318 * 106 7/16/99 1:50p Dave
319 * 8 bit aabitmaps. yay.
321 * 105 7/15/99 3:07p Dave
322 * 32 bit detection support. Mouse coord commandline.
324 * 104 7/15/99 2:13p Dave
325 * Added 32 bit detection.
327 * 103 7/15/99 9:20a Andsager
328 * FS2_DEMO initial checkin
330 * 102 7/14/99 11:02a Dave
331 * Skill level default back to easy. Blech.
333 * 101 7/09/99 5:54p Dave
334 * Seperated cruiser types into individual types. Added tons of new
335 * briefing icons. Campaign screen.
337 * 100 7/08/99 4:43p Andsager
338 * New check for sparky_hi and print if not found.
340 * 99 7/08/99 10:53a Dave
341 * New multiplayer interpolation scheme. Not 100% done yet, but still
342 * better than the old way.
344 * 98 7/06/99 4:24p Dave
345 * Mid-level checkin. Starting on some potentially cool multiplayer
348 * 97 7/06/99 3:35p Andsager
349 * Allow movie to play before red alert mission.
351 * 96 7/03/99 5:50p Dave
352 * Make rotated bitmaps draw properly in padlock views.
354 * 95 7/02/99 9:55p Dave
355 * Player engine wash sound.
357 * 94 7/02/99 4:30p Dave
358 * Much more sophisticated lightning support.
360 * 93 6/29/99 7:52p Dave
361 * Put in exception handling in FS2.
363 * 92 6/22/99 9:37p Dave
364 * Put in pof spewing.
366 * 91 6/16/99 4:06p Dave
367 * New pilot info popup. Added new draw-bitmap-as-poly function.
369 * 90 6/15/99 1:56p Andsager
370 * For release builds, allow start up in high res only with
373 * 89 6/15/99 9:34a Dave
374 * Fixed key checking in single threaded version of the stamp notification
377 * 88 6/09/99 2:55p Andsager
378 * Allow multiple asteroid subtypes (of large, medium, small) and follow
381 * 87 6/08/99 1:14a Dave
382 * Multi colored hud test.
384 * 86 6/04/99 9:52a Dave
385 * Fixed some rendering problems.
387 * 85 6/03/99 10:15p Dave
388 * Put in temporary main hall screen.
390 * 84 6/02/99 6:18p Dave
391 * Fixed TNT lockup problems! Wheeeee!
393 * 83 6/01/99 3:52p Dave
394 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
395 * dead popup, pxo find player popup, pxo private room popup.
397 * 82 5/26/99 1:28p Jasenw
398 * changed coords for loading ani
400 * 81 5/26/99 11:46a Dave
401 * Added ship-blasting lighting and made the randomization of lighting
402 * much more customizable.
404 * 80 5/24/99 5:45p Dave
405 * Added detail levels to the nebula, with a decent speedup. Split nebula
406 * lightning into its own section.
419 #include "systemvars.h"
424 #include "starfield.h"
425 #include "lighting.h"
430 #include "fireballs.h"
434 #include "floating.h"
435 #include "gamesequence.h"
437 #include "optionsmenu.h"
438 #include "playermenu.h"
439 #include "trainingmenu.h"
440 #include "techmenu.h"
443 #include "hudmessage.h"
445 #include "missiongoals.h"
446 #include "missionparse.h"
451 #include "multiutil.h"
452 #include "multimsgs.h"
456 #include "freespace.h"
457 #include "managepilot.h"
459 #include "contexthelp.h"
462 #include "missionbrief.h"
463 #include "missiondebrief.h"
465 #include "missionshipchoice.h"
467 #include "hudconfig.h"
468 #include "controlsconfig.h"
469 #include "missionmessage.h"
470 #include "missiontraining.h"
472 #include "hudtarget.h"
476 #include "eventmusic.h"
477 #include "animplay.h"
478 #include "missionweaponchoice.h"
479 #include "missionlog.h"
480 #include "audiostr.h"
482 #include "missioncampaign.h"
484 #include "missionhotkey.h"
485 #include "objectsnd.h"
486 #include "cmeasure.h"
488 #include "linklist.h"
489 #include "shockwave.h"
490 #include "afterburner.h"
495 #include "stand_gui.h"
496 #include "pcxutils.h"
497 #include "hudtargetbox.h"
498 #include "multi_xfer.h"
499 #include "hudescort.h"
500 #include "multiutil.h"
503 #include "multiteamselect.h"
506 #include "readyroom.h"
507 #include "mainhallmenu.h"
508 #include "multilag.h"
510 #include "particle.h"
512 #include "multi_ingame.h"
513 #include "snazzyui.h"
514 #include "asteroid.h"
515 #include "popupdead.h"
516 #include "multi_voice.h"
517 #include "missioncmdbrief.h"
518 #include "redalert.h"
519 #include "gameplayhelp.h"
520 #include "multilag.h"
521 #include "staticrand.h"
522 #include "multi_pmsg.h"
523 #include "levelpaging.h"
524 #include "observer.h"
525 #include "multi_pause.h"
526 #include "multi_endgame.h"
527 #include "cutscenes.h"
528 #include "multi_respawn.h"
529 // #include "movie.h"
530 #include "multi_obj.h"
531 #include "multi_log.h"
533 #include "localize.h"
534 #include "osregistry.h"
535 #include "barracks.h"
536 #include "missionpause.h"
538 #include "alphacolors.h"
539 #include "objcollide.h"
542 #include "neblightning.h"
543 #include "shipcontrails.h"
546 #include "multi_dogfight.h"
547 #include "multi_rate.h"
548 #include "muzzleflash.h"
552 #include "mainhalltemp.h"
553 #include "exceptionhandler.h"
555 #include "supernova.h"
556 #include "hudshield.h"
558 // #include "names.h"
560 #include "missionloopbrief.h"
564 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
570 // 1.00.04 5/26/98 MWA -- going final (12 pm)
571 // 1.00.03 5/26/98 MWA -- going final (3 am)
572 // 1.00.02 5/25/98 MWA -- going final
573 // 1.00.01 5/25/98 MWA -- going final
574 // 0.90 5/21/98 MWA -- getting ready for final.
575 // 0.10 4/9/98. Set by MK.
577 // Demo version: (obsolete since DEMO codebase split from tree)
578 // 0.03 4/10/98 AL. Interplay rev
579 // 0.02 4/8/98 MK. Increased when this system was modified.
580 // 0.01 4/7/98? AL. First release to Interplay QA.
583 // 1.00 5/28/98 AL. First release to Interplay QA.
585 void game_level_init(int seed = -1);
586 void game_post_level_init();
587 void game_do_frame();
588 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
589 void game_reset_time();
590 void game_show_framerate(); // draws framerate in lower right corner
592 int Game_no_clear = 0;
594 int Pofview_running = 0;
595 int Nebedit_running = 0;
597 typedef struct big_expl_flash {
598 float max_flash_intensity; // max intensity
599 float cur_flash_intensity; // cur intensity
600 int flash_start; // start time
603 #define FRAME_FILTER 16
605 #define DEFAULT_SKILL_LEVEL 1
606 int Game_skill_level = DEFAULT_SKILL_LEVEL;
608 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
609 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
611 #define EXE_FNAME ("fs2.exe")
612 #define LAUNCHER_FNAME ("freespace2.exe")
614 // JAS: Code for warphole camera.
615 // Needs to be cleaned up.
616 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
617 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
618 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
619 matrix Camera_orient = IDENTITY_MATRIX;
620 float Camera_damping = 1.0f;
621 float Camera_time = 0.0f;
622 float Warpout_time = 0.0f;
623 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
624 int Warpout_sound = -1;
626 int Use_joy_mouse = 0;
627 int Use_palette_flash = 1;
629 int Use_fullscreen_at_startup = 0;
631 int Show_area_effect = 0;
632 object *Last_view_target = NULL;
634 int dogfight_blown = 0;
637 float frametimes[FRAME_FILTER];
638 float frametotal = 0.0f;
642 int Show_framerate = 0;
644 int Show_framerate = 1;
647 int Framerate_cap = 120;
650 int Show_target_debug_info = 0;
651 int Show_target_weapons = 0;
653 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
655 int Debug_octant = -1;
657 fix Game_time_compression = F1_0;
659 // if the ships.tbl the player has is valid
660 int Game_ships_tbl_valid = 0;
662 // if the weapons.tbl the player has is valid
663 int Game_weapons_tbl_valid = 0;
667 extern int Player_attacking_enabled;
671 int Pre_player_entry;
673 int Fred_running = 0;
674 char Game_current_mission_filename[MAX_FILENAME_LEN];
675 int game_single_step = 0;
676 int last_single_step=0;
678 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
679 extern int MSG_WINDOW_Y_START;
680 extern int MSG_WINDOW_HEIGHT;
682 int game_zbuffer = 1;
683 //static int Game_music_paused;
684 static int Game_paused;
688 #define EXPIRE_BAD_CHECKSUM 1
689 #define EXPIRE_BAD_TIME 2
691 extern void ssm_init();
692 extern void ssm_level_init();
693 extern void ssm_process();
695 // static variable to contain the time this version was built
696 // commented out for now until
697 // I figure out how to get the username into the file
698 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
700 // defines and variables used for dumping frame for making trailers.
702 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
703 int Debug_dump_trigger = 0;
704 int Debug_dump_frame_count;
705 int Debug_dump_frame_num = 0;
706 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
709 // amount of time to wait after the player has died before we display the death died popup
710 #define PLAYER_DIED_POPUP_WAIT 2500
711 int Player_died_popup_wait = -1;
712 int Player_multi_died_check = -1;
714 // builtin mission list stuff
716 int Game_builtin_mission_count = 6;
717 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
718 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
719 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
720 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
721 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
722 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
723 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
725 #elif defined(PD_BUILD)
726 int Game_builtin_mission_count = 4;
727 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
728 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
729 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
730 { "sm1-01", (FSB_FROM_VOLITION), "" },
731 { "sm1-05", (FSB_FROM_VOLITION), "" },
733 #elif defined(MULTIPLAYER_BETA)
734 int Game_builtin_mission_count = 17;
735 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
737 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
738 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
739 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
740 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
741 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
742 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
743 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
744 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
745 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
746 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
747 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
748 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
749 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
750 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
751 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
752 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
753 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
755 #elif defined(OEM_BUILD)
756 int Game_builtin_mission_count = 17;
757 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
758 // oem version - act 1 only
759 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
762 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
763 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
764 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
765 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
766 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
767 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
768 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
769 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
770 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
771 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
772 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
773 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
774 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
775 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
776 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
777 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
780 int Game_builtin_mission_count = 92;
781 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
782 // single player campaign
783 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
786 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
787 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
788 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
789 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
790 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
791 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
792 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
793 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
794 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
795 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
796 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
797 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
798 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
799 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
800 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
801 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
802 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
803 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
804 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
807 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
808 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
809 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
810 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
811 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
812 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
813 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
814 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
815 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
816 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
819 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
820 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
821 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
822 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
823 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
824 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
825 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
826 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
827 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
828 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
829 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
830 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
832 // multiplayer missions
835 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
841 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
846 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
847 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
848 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
849 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
852 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
855 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
858 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
859 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
861 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
862 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
864 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
865 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
889 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
890 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
891 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
892 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
897 // Internal function prototypes
898 void game_maybe_draw_mouse(float frametime);
899 void init_animating_pointer();
900 void load_animating_pointer(char *filename, int dx, int dy);
901 void unload_animating_pointer();
902 void game_do_training_checks();
903 void game_shutdown(void);
904 void game_show_event_debug(float frametime);
905 void game_event_debug_init();
907 void demo_upsell_show_screens();
908 void game_start_subspace_ambient_sound();
909 void game_stop_subspace_ambient_sound();
910 void verify_ships_tbl();
911 void verify_weapons_tbl();
912 void display_title_screen();
914 // loading background filenames
915 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
916 "LoadingBG", // GR_640
917 "2_LoadingBG" // GR_1024
921 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
922 "Loading.ani", // GR_640
923 "2_Loading.ani" // GR_1024
926 #if defined(FS2_DEMO)
927 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
931 #elif defined(OEM_BUILD)
932 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
939 char Game_CDROM_dir[MAX_PATH_LEN];
942 // How much RAM is on this machine. Set in WinMain
943 uint Freespace_total_ram = 0;
946 float Game_flash_red = 0.0f;
947 float Game_flash_green = 0.0f;
948 float Game_flash_blue = 0.0f;
949 float Sun_spot = 0.0f;
950 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
952 // game shudder stuff (in ms)
953 int Game_shudder_time = -1;
954 int Game_shudder_total = 0;
955 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
958 sound_env Game_sound_env;
959 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
960 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
962 int Game_sound_env_update_timestamp;
964 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
967 // WARPIN CRAP END --------------------------------------------------------------------------------------------
969 fs_builtin_mission *game_find_builtin_mission(char *filename)
973 // look through all existing builtin missions
974 for(idx=0; idx<Game_builtin_mission_count; idx++){
975 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
976 return &Game_builtin_mission_list[idx];
984 int game_get_default_skill_level()
986 return DEFAULT_SKILL_LEVEL;
990 void game_flash_reset()
992 Game_flash_red = 0.0f;
993 Game_flash_green = 0.0f;
994 Game_flash_blue = 0.0f;
996 Big_expl_flash.max_flash_intensity = 0.0f;
997 Big_expl_flash.cur_flash_intensity = 0.0f;
998 Big_expl_flash.flash_start = 0;
1001 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1002 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1004 void game_framerate_check_init()
1006 // zero critical time
1007 Gf_critical_time = 0.0f;
1010 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1011 // if this is a glide card
1012 if(gr_screen.mode == GR_GLIDE){
1013 extern GrHwConfiguration hwconfig;
1016 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1017 Gf_critical = 15.0f;
1021 Gf_critical = 10.0f;
1024 // d3d. only care about good cards here I guess (TNT)
1026 Gf_critical = 15.0f;
1029 // if this is a glide card
1030 if(gr_screen.mode == GR_GLIDE){
1031 extern GrHwConfiguration hwconfig;
1034 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1035 Gf_critical = 25.0f;
1039 Gf_critical = 20.0f;
1042 // d3d. only care about good cards here I guess (TNT)
1044 Gf_critical = 25.0f;
1049 extern float Framerate;
1050 void game_framerate_check()
1054 // if the current framerate is above the critical level, add frametime
1055 if(Framerate >= Gf_critical){
1056 Gf_critical_time += flFrametime;
1059 if(!Show_framerate){
1063 // display if we're above the critical framerate
1064 if(Framerate < Gf_critical){
1065 gr_set_color_fast(&Color_bright_red);
1066 gr_string(200, y_start, "Framerate warning");
1071 // display our current pct of good frametime
1072 if(f2fl(Missiontime) >= 0.0f){
1073 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1076 gr_set_color_fast(&Color_bright_green);
1078 gr_set_color_fast(&Color_bright_red);
1081 gr_printf(200, y_start, "%d%%", (int)pct);
1088 // Adds a flash effect. These can be positive or negative.
1089 // The range will get capped at around -1 to 1, so stick
1090 // with a range like that.
1091 void game_flash( float r, float g, float b )
1093 Game_flash_red += r;
1094 Game_flash_green += g;
1095 Game_flash_blue += b;
1097 if ( Game_flash_red < -1.0f ) {
1098 Game_flash_red = -1.0f;
1099 } else if ( Game_flash_red > 1.0f ) {
1100 Game_flash_red = 1.0f;
1103 if ( Game_flash_green < -1.0f ) {
1104 Game_flash_green = -1.0f;
1105 } else if ( Game_flash_green > 1.0f ) {
1106 Game_flash_green = 1.0f;
1109 if ( Game_flash_blue < -1.0f ) {
1110 Game_flash_blue = -1.0f;
1111 } else if ( Game_flash_blue > 1.0f ) {
1112 Game_flash_blue = 1.0f;
1117 // Adds a flash for Big Ship explosions
1118 // cap range from 0 to 1
1119 void big_explosion_flash(float flash)
1121 Big_expl_flash.flash_start = timestamp(1);
1125 } else if (flash < 0.0f) {
1129 Big_expl_flash.max_flash_intensity = flash;
1130 Big_expl_flash.cur_flash_intensity = 0.0f;
1133 // Amount to diminish palette towards normal, per second.
1134 #define DIMINISH_RATE 0.75f
1135 #define SUN_DIMINISH_RATE 6.00f
1139 float sn_glare_scale = 1.7f;
1142 dc_get_arg(ARG_FLOAT);
1143 sn_glare_scale = Dc_arg_float;
1146 float Supernova_last_glare = 0.0f;
1147 void game_sunspot_process(float frametime)
1151 float Sun_spot_goal = 0.0f;
1154 sn_stage = supernova_active();
1156 // sunspot differently based on supernova stage
1158 // approaching. player still in control
1161 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1164 light_get_global_dir(&light_dir, 0);
1166 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1169 // scale it some more
1170 dot = dot * (0.5f + (pct * 0.5f));
1173 Sun_spot_goal += (dot * sn_glare_scale);
1176 // draw the sun glow
1177 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1178 // draw the glow for this sun
1179 stars_draw_sun_glow(0);
1182 Supernova_last_glare = Sun_spot_goal;
1185 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1188 Sun_spot_goal = 0.9f;
1189 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1191 if(Sun_spot_goal > 1.0f){
1192 Sun_spot_goal = 1.0f;
1195 Sun_spot_goal *= sn_glare_scale;
1196 Supernova_last_glare = Sun_spot_goal;
1199 // fade to white. display dead popup
1202 Supernova_last_glare += (2.0f * flFrametime);
1203 if(Supernova_last_glare > 2.0f){
1204 Supernova_last_glare = 2.0f;
1207 Sun_spot_goal = Supernova_last_glare;
1214 // check sunspots for all suns
1215 n_lights = light_get_global_count();
1218 for(idx=0; idx<n_lights; idx++){
1219 //(vector *eye_pos, matrix *eye_orient)
1220 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1223 light_get_global_dir(&light_dir, idx);
1225 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1227 Sun_spot_goal += (float)pow(dot,85.0f);
1229 // draw the glow for this sun
1230 stars_draw_sun_glow(idx);
1232 Sun_spot_goal = 0.0f;
1238 Sun_spot_goal = 0.0f;
1242 float dec_amount = frametime*SUN_DIMINISH_RATE;
1244 if ( Sun_spot < Sun_spot_goal ) {
1245 Sun_spot += dec_amount;
1246 if ( Sun_spot > Sun_spot_goal ) {
1247 Sun_spot = Sun_spot_goal;
1249 } else if ( Sun_spot > Sun_spot_goal ) {
1250 Sun_spot -= dec_amount;
1251 if ( Sun_spot < Sun_spot_goal ) {
1252 Sun_spot = Sun_spot_goal;
1258 // Call once a frame to diminish the
1259 // flash effect to 0.
1260 void game_flash_diminish(float frametime)
1262 float dec_amount = frametime*DIMINISH_RATE;
1264 if ( Game_flash_red > 0.0f ) {
1265 Game_flash_red -= dec_amount;
1266 if ( Game_flash_red < 0.0f )
1267 Game_flash_red = 0.0f;
1269 Game_flash_red += dec_amount;
1270 if ( Game_flash_red > 0.0f )
1271 Game_flash_red = 0.0f;
1274 if ( Game_flash_green > 0.0f ) {
1275 Game_flash_green -= dec_amount;
1276 if ( Game_flash_green < 0.0f )
1277 Game_flash_green = 0.0f;
1279 Game_flash_green += dec_amount;
1280 if ( Game_flash_green > 0.0f )
1281 Game_flash_green = 0.0f;
1284 if ( Game_flash_blue > 0.0f ) {
1285 Game_flash_blue -= dec_amount;
1286 if ( Game_flash_blue < 0.0f )
1287 Game_flash_blue = 0.0f;
1289 Game_flash_blue += dec_amount;
1290 if ( Game_flash_blue > 0.0f )
1291 Game_flash_blue = 0.0f;
1294 // update big_explosion_cur_flash
1295 #define TIME_UP 1500
1296 #define TIME_DOWN 2500
1297 int duration = TIME_UP + TIME_DOWN;
1298 int time = timestamp_until(Big_expl_flash.flash_start);
1299 if (time > -duration) {
1301 if (time < TIME_UP) {
1302 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1305 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1309 if ( Use_palette_flash ) {
1311 static int or=0, og=0, ob=0;
1313 // Change the 200 to change the color range of colors.
1314 r = fl2i( Game_flash_red*128.0f );
1315 g = fl2i( Game_flash_green*128.0f );
1316 b = fl2i( Game_flash_blue*128.0f );
1318 if ( Sun_spot > 0.0f ) {
1319 r += fl2i(Sun_spot*128.0f);
1320 g += fl2i(Sun_spot*128.0f);
1321 b += fl2i(Sun_spot*128.0f);
1324 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1325 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1326 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1327 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1330 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1331 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1332 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1334 if ( (r!=0) || (g!=0) || (b!=0) ) {
1335 gr_flash( r, g, b );
1337 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1348 void game_level_close()
1350 // De-Initialize the game subsystems
1351 message_mission_shutdown();
1352 event_music_level_close();
1353 game_stop_looped_sounds();
1355 obj_snd_level_close(); // uninit object-linked persistant sounds
1356 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1357 anim_level_close(); // stop and clean up any anim instances
1358 shockwave_level_close();
1359 fireball_level_close();
1361 mission_event_shutdown();
1362 asteroid_level_close();
1363 model_cache_reset(); // Reset/free all the model caching stuff
1364 flak_level_close(); // unload flak stuff
1365 neb2_level_close(); // shutdown gaseous nebula stuff
1368 mflash_level_close();
1370 audiostream_unpause_all();
1375 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1376 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1377 void game_level_init(int seed)
1379 // seed the random number generator
1381 // if no seed was passed, seed the generator either from the time value, or from the
1382 // netgame security flags -- ensures that all players in multiplayer game will have the
1383 // same randon number sequence (with static rand functions)
1384 if ( Game_mode & GM_NORMAL ) {
1385 Game_level_seed = time(NULL);
1387 Game_level_seed = Netgame.security;
1390 // mwa 9/17/98 -- maybe this assert isn't needed????
1391 Assert( !(Game_mode & GM_MULTIPLAYER) );
1392 Game_level_seed = seed;
1394 srand( Game_level_seed );
1396 // semirand function needs to get re-initted every time in multiplayer
1397 if ( Game_mode & GM_MULTIPLAYER ){
1403 Key_normal_game = (Game_mode & GM_NORMAL);
1406 Game_shudder_time = -1;
1408 // Initialize the game subsystems
1409 // timestamp_reset(); // Must be inited before everything else
1411 game_reset_time(); // resets time, and resets saved time too
1413 obj_init(); // Must be inited before the other systems
1414 model_free_all(); // Free all existing models
1415 mission_brief_common_init(); // Free all existing briefing/debriefing text
1416 weapon_level_init();
1417 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1419 player_level_init();
1420 shipfx_flash_init(); // Init the ship gun flash system.
1421 game_flash_reset(); // Reset the flash effect
1422 particle_init(); // Reset the particle system
1426 shield_hit_init(); // Initialize system for showing shield hits
1427 radar_mission_init();
1428 mission_init_goals();
1431 obj_snd_level_init(); // init object-linked persistant sounds
1433 shockwave_level_init();
1434 afterburner_level_init();
1435 scoring_level_init( &Player->stats );
1437 asteroid_level_init();
1438 control_config_clear_used_status();
1439 collide_ship_ship_sounds_init();
1441 Pre_player_entry = 1; // Means the player has not yet entered.
1442 Entry_delay_time = 0; // Could get overwritten in mission read.
1443 fireball_preload(); // page in warphole bitmaps
1445 flak_level_init(); // initialize flak - bitmaps, etc
1446 ct_level_init(); // initialize ships contrails, etc
1447 awacs_level_init(); // initialize AWACS
1448 beam_level_init(); // initialize beam weapons
1449 mflash_level_init();
1451 supernova_level_init();
1453 // multiplayer dogfight hack
1456 shipfx_engine_wash_level_init();
1460 Last_view_target = NULL;
1465 // campaign wasn't ended
1466 Campaign_ended_in_mission = 0;
1469 // called when a mission is over -- does server specific stuff.
1470 void freespace_stop_mission()
1473 Game_mode &= ~GM_IN_MISSION;
1476 // called at frame interval to process networking stuff
1477 void game_do_networking()
1479 Assert( Net_player != NULL );
1480 if (!(Game_mode & GM_MULTIPLAYER)){
1484 // see if this player should be reading/writing data. Bit is set when at join
1485 // screen onward until quits back to main menu.
1486 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1490 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1493 multi_pause_do_frame();
1498 // Loads the best palette for this level, based
1499 // on nebula color and hud color. You could just call palette_load_table with
1500 // the appropriate filename, but who wants to do that.
1501 void game_load_palette()
1503 char palette_filename[1024];
1505 // We only use 3 hud colors right now
1506 // Assert( HUD_config.color >= 0 );
1507 // Assert( HUD_config.color <= 2 );
1509 Assert( Mission_palette >= 0 );
1510 Assert( Mission_palette <= 98 );
1512 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1513 strcpy( palette_filename, NOX("gamepalette-subspace") );
1515 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1518 mprintf(( "Loading palette %s\n", palette_filename ));
1520 // palette_load_table(palette_filename);
1523 void game_post_level_init()
1525 // Stuff which gets called after mission is loaded. Because player isn't created until
1526 // after mission loads, some things must get initted after the level loads
1528 model_level_post_init();
1531 hud_setup_escort_list();
1532 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1538 game_event_debug_init();
1541 training_mission_init();
1542 asteroid_create_all();
1544 game_framerate_check_init();
1548 // An estimate as to how high the count passed to game_loading_callback will go.
1549 // This is just a guess, it seems to always be about the same. The count is
1550 // proportional to the code being executed, not the time, so this works good
1551 // for a bar, assuming the code does about the same thing each time you
1552 // load a level. You can find this value by looking at the return value
1553 // of game_busy_callback(NULL), which I conveniently print out to the
1554 // debug output window with the '=== ENDING LOAD ==' stuff.
1555 //#define COUNT_ESTIMATE 3706
1556 #define COUNT_ESTIMATE 1111
1558 int Game_loading_callback_inited = 0;
1560 int Game_loading_background = -1;
1561 anim * Game_loading_ani = NULL;
1562 anim_instance *Game_loading_ani_instance;
1563 int Game_loading_frame=-1;
1565 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1574 // This gets called 10x per second and count is the number of times
1575 // game_busy() has been called since the current callback function
1577 void game_loading_callback(int count)
1579 game_do_networking();
1581 Assert( Game_loading_callback_inited==1 );
1582 Assert( Game_loading_ani != NULL );
1584 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1585 if ( framenum > Game_loading_ani->total_frames-1 ) {
1586 framenum = Game_loading_ani->total_frames-1;
1587 } else if ( framenum < 0 ) {
1592 while ( Game_loading_frame < framenum ) {
1593 Game_loading_frame++;
1594 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1598 if ( cbitmap > -1 ) {
1599 if ( Game_loading_background > -1 ) {
1600 gr_set_bitmap( Game_loading_background );
1604 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1605 gr_set_bitmap( cbitmap );
1606 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1608 bm_release(cbitmap);
1614 void game_loading_callback_init()
1616 Assert( Game_loading_callback_inited==0 );
1618 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1619 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1622 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1623 Assert( Game_loading_ani != NULL );
1624 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1625 Assert( Game_loading_ani_instance != NULL );
1626 Game_loading_frame = -1;
1628 Game_loading_callback_inited = 1;
1630 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1635 void game_loading_callback_close()
1637 Assert( Game_loading_callback_inited==1 );
1639 // Make sure bar shows all the way over.
1640 game_loading_callback(COUNT_ESTIMATE);
1642 int real_count = game_busy_callback( NULL );
1645 Game_loading_callback_inited = 0;
1648 mprintf(( "=================== ENDING LOAD ================\n" ));
1649 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1650 mprintf(( "================================================\n" ));
1652 // to remove warnings in release build
1656 free_anim_instance(Game_loading_ani_instance);
1657 Game_loading_ani_instance = NULL;
1658 anim_free(Game_loading_ani);
1659 Game_loading_ani = NULL;
1661 bm_release( Game_loading_background );
1662 common_free_interface_palette(); // restore game palette
1663 Game_loading_background = -1;
1665 gr_set_font( FONT1 );
1668 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1670 void game_maybe_update_sound_environment()
1672 // do nothing for now
1675 // Assign the sound environment for the game, based on the current mission
1677 void game_assign_sound_environment()
1680 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1681 Game_sound_env.id = SND_ENV_DRUGGED;
1682 Game_sound_env.volume = 0.800f;
1683 Game_sound_env.damping = 1.188f;
1684 Game_sound_env.decay = 6.392f;
1686 } else if (Num_asteroids > 30) {
1687 Game_sound_env.id = SND_ENV_AUDITORIUM;
1688 Game_sound_env.volume = 0.603f;
1689 Game_sound_env.damping = 0.5f;
1690 Game_sound_env.decay = 4.279f;
1693 Game_sound_env = Game_default_sound_env;
1697 Game_sound_env = Game_default_sound_env;
1698 Game_sound_env_update_timestamp = timestamp(1);
1701 // function which gets called before actually entering the mission. It is broken down into a funciton
1702 // since it will get called in one place from a single player game and from another place for
1703 // a multiplayer game
1704 void freespace_mission_load_stuff()
1706 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1707 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1708 if(!(Game_mode & GM_STANDALONE_SERVER)){
1710 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1712 game_loading_callback_init();
1714 event_music_level_init(); // preloads the first 2 seconds for each event music track
1717 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1720 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1723 ship_assign_sound_all(); // assign engine sounds to ships
1724 game_assign_sound_environment(); // assign the sound environment for this mission
1727 // call function in missionparse.cpp to fixup player/ai stuff.
1728 mission_parse_fixup_players();
1731 // Load in all the bitmaps for this level
1736 game_loading_callback_close();
1738 // the only thing we need to call on the standalone for now.
1740 // call function in missionparse.cpp to fixup player/ai stuff.
1741 mission_parse_fixup_players();
1743 // Load in all the bitmaps for this level
1749 uint load_mission_load;
1750 uint load_post_level_init;
1751 uint load_mission_stuff;
1753 // tells the server to load the mission and initialize structures
1754 int game_start_mission()
1756 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1758 load_gl_init = time(NULL);
1760 load_gl_init = time(NULL) - load_gl_init;
1762 if (Game_mode & GM_MULTIPLAYER) {
1763 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1765 // clear multiplayer stats
1766 init_multiplayer_stats();
1769 load_mission_load = time(NULL);
1770 if (mission_load()) {
1771 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1772 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1773 gameseq_post_event(GS_EVENT_MAIN_MENU);
1775 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1780 load_mission_load = time(NULL) - load_mission_load;
1782 // If this is a red alert mission in campaign mode, bash wingman status
1783 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1784 red_alert_bash_wingman_status();
1787 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1788 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1789 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1790 // game_load_palette();
1793 load_post_level_init = time(NULL);
1794 game_post_level_init();
1795 load_post_level_init = time(NULL) - load_post_level_init;
1799 void Do_model_timings_test();
1800 Do_model_timings_test();
1804 load_mission_stuff = time(NULL);
1805 freespace_mission_load_stuff();
1806 load_mission_stuff = time(NULL) - load_mission_stuff;
1811 int Interface_framerate = 0;
1814 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1815 DCF_BOOL( show_framerate, Show_framerate )
1816 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1817 DCF_BOOL( show_target_weapons, Show_target_weapons )
1818 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1819 DCF_BOOL( sound, Sound_enabled )
1820 DCF_BOOL( zbuffer, game_zbuffer )
1821 DCF_BOOL( shield_system, New_shield_system )
1822 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1823 DCF_BOOL( player_attacking, Player_attacking_enabled )
1824 DCF_BOOL( show_waypoints, Show_waypoints )
1825 DCF_BOOL( show_area_effect, Show_area_effect )
1826 DCF_BOOL( show_net_stats, Show_net_stats )
1827 DCF_BOOL( log, Log_debug_output_to_file )
1828 DCF_BOOL( training_msg_method, Training_msg_method )
1829 DCF_BOOL( show_player_pos, Show_player_pos )
1830 DCF_BOOL(i_framerate, Interface_framerate )
1832 DCF(show_mem,"Toggles showing mem usage")
1835 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1836 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1837 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1838 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1844 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1846 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1847 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1851 DCF(show_cpu,"Toggles showing cpu usage")
1854 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1855 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1856 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1857 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1863 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1865 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1866 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1873 // AL 4-8-98: always allow players to display their framerate
1876 DCF_BOOL( show_framerate, Show_framerate )
1883 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1886 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1887 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1888 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1889 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1891 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" );
1892 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1894 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1897 DCF(palette_flash,"Toggles palette flash effect on/off")
1900 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1901 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1902 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1903 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1905 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1906 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1909 int Use_low_mem = 0;
1911 DCF(low_mem,"Uses low memory settings regardless of RAM")
1914 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1915 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1916 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1917 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1919 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1920 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1922 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1928 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1931 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1932 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1933 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1934 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1936 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1937 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1938 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1942 int Framerate_delay = 0;
1944 float Freespace_gamma = 1.0f;
1946 DCF(gamma,"Sets Gamma factor")
1949 dc_get_arg(ARG_FLOAT|ARG_NONE);
1950 if ( Dc_arg_type & ARG_FLOAT ) {
1951 Freespace_gamma = Dc_arg_float;
1953 dc_printf( "Gamma reset to 1.0f\n" );
1954 Freespace_gamma = 1.0f;
1956 if ( Freespace_gamma < 0.1f ) {
1957 Freespace_gamma = 0.1f;
1958 } else if ( Freespace_gamma > 5.0f ) {
1959 Freespace_gamma = 5.0f;
1961 gr_set_gamma(Freespace_gamma);
1963 char tmp_gamma_string[32];
1964 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1965 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1969 dc_printf( "Usage: gamma <float>\n" );
1970 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
1971 Dc_status = 0; // don't print status if help is printed. Too messy.
1975 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
1984 Game_current_mission_filename[0] = 0;
1986 // seed the random number generator
1987 Game_init_seed = time(NULL);
1988 srand( Game_init_seed );
1990 Framerate_delay = 0;
1996 extern void bm_init();
2002 // Initialize the timer before the os
2009 GetCurrentDirectory(1024, whee);
2011 strcat(whee, EXE_FNAME);
2013 //Initialize the libraries
2014 s1 = timer_get_milliseconds();
2015 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2018 e1 = timer_get_milliseconds();
2020 // time a bunch of cfopens
2022 s2 = timer_get_milliseconds();
2024 for(int idx=0; idx<10000; idx++){
2025 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2030 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2032 e2 = timer_get_milliseconds();
2035 if (Is_standalone) {
2036 std_init_standalone();
2038 os_init( Osreg_class_name, Osreg_app_name );
2039 os_set_title(Osreg_title);
2042 // initialize localization module. Make sure this is down AFTER initialzing OS.
2043 // int t1 = timer_get_milliseconds();
2046 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2048 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2051 // verify that he has a valid weapons.tbl
2052 verify_weapons_tbl();
2054 // Output version numbers to registry for auto patching purposes
2055 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2056 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2057 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2059 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2060 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2061 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2064 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2068 Asteroids_enabled = 1;
2071 /////////////////////////////
2073 /////////////////////////////
2078 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2079 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2081 if (!stricmp(ptr, NOX("no sound"))) {
2082 Cmdline_freespace_no_sound = 1;
2084 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2086 } else if (!stricmp(ptr, NOX("EAX"))) {
2091 if (!Is_standalone) {
2092 snd_init(use_a3d, use_eax);
2094 /////////////////////////////
2096 /////////////////////////////
2098 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2100 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);
2102 // fire up the UpdateLauncher executable
2104 PROCESS_INFORMATION pi;
2106 memset( &si, 0, sizeof(STARTUPINFO) );
2109 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2110 NULL, // pointer to command line string
2111 NULL, // pointer to process security attributes
2112 NULL, // pointer to thread security attributes
2113 FALSE, // handle inheritance flag
2114 CREATE_DEFAULT_ERROR_MODE, // creation flags
2115 NULL, // pointer to new environment block
2116 NULL, // pointer to current directory name
2117 &si, // pointer to STARTUPINFO
2118 &pi // pointer to PROCESS_INFORMATION
2121 // If the Launcher could not be started up, let the user know
2123 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2130 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2131 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);
2136 // check for hi res pack file
2137 int has_sparky_hi = 0;
2139 // check if sparky_hi exists -- access mode 0 means does file exist
2142 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2145 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2148 // see if we've got 32 bit in the string
2149 if(strstr(ptr, "32 bit")){
2155 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2157 // always 640 for E3
2158 gr_init(GR_640, GR_GLIDE);
2160 // regular or hi-res ?
2162 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2164 if(strstr(ptr, NOX("(1024x768)"))){
2166 gr_init(GR_1024, GR_GLIDE);
2168 gr_init(GR_640, GR_GLIDE);
2171 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2173 // always 640 for E3
2175 gr_init(GR_640, GR_DIRECT3D, depth);
2177 // regular or hi-res ?
2179 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2181 if(strstr(ptr, NOX("(1024x768)"))){
2185 gr_init(GR_1024, GR_DIRECT3D, depth);
2189 gr_init(GR_640, GR_DIRECT3D, depth);
2195 if ( Use_fullscreen_at_startup && !Is_standalone) {
2196 gr_init(GR_640, GR_DIRECTDRAW);
2198 gr_init(GR_640, GR_SOFTWARE);
2201 if ( !Is_standalone ) {
2202 gr_init(GR_640, GR_DIRECTDRAW);
2204 gr_init(GR_640, GR_SOFTWARE);
2210 extern int Gr_inited;
2211 if(trying_d3d && !Gr_inited){
2212 extern char Device_init_error[512];
2213 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2219 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2220 Freespace_gamma = (float)atof(ptr);
2221 if ( Freespace_gamma < 0.1f ) {
2222 Freespace_gamma = 0.1f;
2223 } else if ( Freespace_gamma > 5.0f ) {
2224 Freespace_gamma = 5.0f;
2226 char tmp_gamma_string[32];
2227 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2228 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2230 gr_set_gamma(Freespace_gamma);
2232 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2235 display_title_screen();
2239 // attempt to load up master tracker registry info (login and password)
2240 Multi_tracker_id = -1;
2242 // pxo login and password
2243 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2245 nprintf(("Network","Error reading in PXO login data\n"));
2246 strcpy(Multi_tracker_login,"");
2248 strcpy(Multi_tracker_login,ptr);
2250 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2252 nprintf(("Network","Error reading PXO password\n"));
2253 strcpy(Multi_tracker_passwd,"");
2255 strcpy(Multi_tracker_passwd,ptr);
2258 // pxo squad name and password
2259 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2261 nprintf(("Network","Error reading in PXO squad name\n"));
2262 strcpy(Multi_tracker_squad_name, "");
2264 strcpy(Multi_tracker_squad_name, ptr);
2267 // If less than 48MB of RAM, use low memory model.
2268 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2269 mprintf(( "Using normal memory settings...\n" ));
2270 bm_set_low_mem(1); // Use every other frame of bitmaps
2272 mprintf(( "Using high memory settings...\n" ));
2273 bm_set_low_mem(0); // Use all frames of bitmaps
2276 // load non-darkening pixel defs
2277 palman_load_pixels();
2279 // hud shield icon stuff
2280 hud_shield_game_init();
2282 control_config_common_init(); // sets up localization stuff in the control config
2288 gamesnd_parse_soundstbl();
2293 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2298 player_controls_init();
2301 //if(!Is_standalone){
2309 ship_init(); // read in ships.tbl
2311 mission_campaign_init(); // load in the default campaign
2313 // navmap_init(); // init the navigation map system
2314 context_help_init();
2315 techroom_intel_init(); // parse species.tbl, load intel info
2317 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2318 init_animating_pointer();
2320 mission_brief_common_init(); // Mark all the briefing structures as empty.
2321 gr_font_init(); // loads up all fonts
2323 neb2_init(); // fullneb stuff
2327 player_tips_init(); // helpful tips
2330 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2331 pilot_load_pic_list();
2332 pilot_load_squad_pic_list();
2334 load_animating_pointer(NOX("cursor"), 0, 0);
2336 // initialize alpha colors
2337 alpha_colors_init();
2340 // Game_music_paused = 0;
2345 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2346 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2348 mprintf(("cfile_init() took %d\n", e1 - s1));
2349 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2352 char transfer_text[128];
2354 float Start_time = 0.0f;
2356 float Framerate = 0.0f;
2358 float Timing_total = 0.0f;
2359 float Timing_render2 = 0.0f;
2360 float Timing_render3 = 0.0f;
2361 float Timing_flip = 0.0f;
2362 float Timing_clear = 0.0f;
2364 MONITOR(NumPolysDrawn);
2370 void game_get_framerate()
2372 char text[128] = "";
2374 if ( frame_int == -1 ) {
2376 for (i=0; i<FRAME_FILTER; i++ ) {
2377 frametimes[i] = 0.0f;
2382 frametotal -= frametimes[frame_int];
2383 frametotal += flFrametime;
2384 frametimes[frame_int] = flFrametime;
2385 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2387 if ( frametotal != 0.0 ) {
2388 if ( Framecount >= FRAME_FILTER )
2389 Framerate = FRAME_FILTER / frametotal;
2391 Framerate = Framecount / frametotal;
2392 sprintf( text, NOX("FPS: %.1f"), Framerate );
2394 sprintf( text, NOX("FPS: ?") );
2398 if (Show_framerate) {
2399 gr_set_color_fast(&HUD_color_debug);
2400 gr_string( 570, 2, text );
2404 void game_show_framerate()
2408 cur_time = f2fl(timer_get_approx_seconds());
2409 if (cur_time - Start_time > 30.0f) {
2410 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2411 Start_time += 1000.0f;
2414 //mprintf(( "%s\n", text ));
2417 if ( Debug_dump_frames )
2421 // possibly show control checking info
2422 control_check_indicate();
2424 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2425 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2426 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2427 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2430 if ( Show_cpu == 1 ) {
2435 dy = gr_get_font_height() + 1;
2437 gr_set_color_fast(&HUD_color_debug);
2440 extern int D3D_textures_in;
2441 extern int D3D_textures_in_frame;
2442 extern int Glide_textures_in;
2443 extern int Glide_textures_in_frame;
2444 extern int Glide_explosion_vram;
2445 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2447 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2449 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2452 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2454 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2456 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2458 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2460 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2465 extern int Num_pairs; // Number of object pairs that were checked.
2466 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2469 extern int Num_pairs_checked; // What percent of object pairs were checked.
2470 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2472 Num_pairs_checked = 0;
2476 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2479 if ( Timing_total > 0.01f ) {
2480 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2482 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2484 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2486 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2488 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2498 dy = gr_get_font_height() + 1;
2500 gr_set_color_fast(&HUD_color_debug);
2503 extern int TotalRam;
2504 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2509 extern int Model_ram;
2510 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2514 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2516 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2518 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2521 extern int D3D_textures_in;
2522 extern int Glide_textures_in;
2523 extern int Glide_textures_in_frame;
2524 extern int Glide_explosion_vram;
2525 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2527 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2529 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2535 if ( Show_player_pos ) {
2539 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));
2542 MONITOR_INC(NumPolys, modelstats_num_polys);
2543 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2544 MONITOR_INC(NumVerts, modelstats_num_verts );
2546 modelstats_num_polys = 0;
2547 modelstats_num_polys_drawn = 0;
2548 modelstats_num_verts = 0;
2549 modelstats_num_sortnorms = 0;
2553 void game_show_standalone_framerate()
2555 float frame_rate=30.0f;
2556 if ( frame_int == -1 ) {
2558 for (i=0; i<FRAME_FILTER; i++ ) {
2559 frametimes[i] = 0.0f;
2564 frametotal -= frametimes[frame_int];
2565 frametotal += flFrametime;
2566 frametimes[frame_int] = flFrametime;
2567 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2569 if ( frametotal != 0.0 ) {
2570 if ( Framecount >= FRAME_FILTER ){
2571 frame_rate = FRAME_FILTER / frametotal;
2573 frame_rate = Framecount / frametotal;
2576 std_set_standalone_fps(frame_rate);
2580 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2581 void game_show_time_left()
2585 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2586 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2587 // checking how much time is left
2589 if ( Mission_end_time == -1 ){
2593 diff = f2i(Mission_end_time - Missiontime);
2594 // be sure to bash to 0. diff could be negative on frame that we quit mission
2599 hud_set_default_color();
2600 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2603 //========================================================================================
2604 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2605 //========================================================================================
2609 DCF(ai_pause,"Pauses ai")
2612 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2613 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2614 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2615 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2618 obj_init_all_ships_physics();
2621 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2622 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2625 DCF(single_step,"Single steps the game")
2628 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2629 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2630 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2631 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2633 last_single_step = 0; // Make so single step waits a frame before stepping
2636 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2637 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2640 DCF_BOOL(physics_pause, physics_paused)
2641 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2642 DCF_BOOL(ai_firing, Ai_firing_enabled )
2644 // Create some simple aliases to these commands...
2645 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2646 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2647 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2648 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2649 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2652 //========================================================================================
2653 //========================================================================================
2656 void game_training_pause_do()
2660 key = game_check_key();
2662 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2669 void game_increase_skill_level()
2672 if (Game_skill_level >= NUM_SKILL_LEVELS){
2673 Game_skill_level = 0;
2677 int Player_died_time;
2679 int View_percent = 100;
2682 DCF(view, "Sets the percent of the 3d view to render.")
2685 dc_get_arg(ARG_INT);
2686 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2687 View_percent = Dc_arg_int;
2689 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2695 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2699 dc_printf("View is set to %d%%\n", View_percent );
2704 // Set the clip region for the 3d rendering window
2705 void game_set_view_clip()
2707 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2708 // Set the clip region for the letterbox "dead view"
2709 int yborder = gr_screen.max_h/4;
2711 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2712 // J.S. I've changed my ways!! See the new "no constants" code!!!
2713 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2715 // Set the clip region for normal view
2716 if ( View_percent >= 100 ) {
2719 int xborder, yborder;
2721 if ( View_percent < 5 ) {
2725 float fp = i2fl(View_percent)/100.0f;
2726 int fi = fl2i(fl_sqrt(fp)*100.0f);
2727 if ( fi > 100 ) fi=100;
2729 xborder = ( gr_screen.max_w*(100-fi) )/200;
2730 yborder = ( gr_screen.max_h*(100-fi) )/200;
2732 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2738 void show_debug_stuff()
2741 int laser_count = 0, missile_count = 0;
2743 for (i=0; i<MAX_OBJECTS; i++) {
2744 if (Objects[i].type == OBJ_WEAPON){
2745 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2747 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2753 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2756 extern int Tool_enabled;
2761 int tst_bitmap = -1;
2763 float tst_offset, tst_offset_total;
2766 void game_tst_frame_pre()
2774 g3_rotate_vertex(&v, &tst_pos);
2775 g3_project_vertex(&v);
2778 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2782 // big ship? always tst
2784 // within 3000 meters
2785 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2789 // within 300 meters
2790 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2797 void game_tst_frame()
2807 tst_time = time(NULL);
2809 // load the tst bitmap
2810 switch((int)frand_range(0.0f, 3.0)){
2812 tst_bitmap = bm_load("ig_jim");
2814 mprintf(("TST 0\n"));
2818 tst_bitmap = bm_load("ig_kan");
2820 mprintf(("TST 1\n"));
2824 tst_bitmap = bm_load("ig_jim");
2826 mprintf(("TST 2\n"));
2830 tst_bitmap = bm_load("ig_kan");
2832 mprintf(("TST 3\n"));
2841 // get the tst bitmap dimensions
2843 bm_get_info(tst_bitmap, &w, &h);
2846 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2848 snd_play(&Snds[SND_VASUDAN_BUP]);
2850 // tst x and direction
2854 tst_offset_total = (float)w;
2855 tst_offset = (float)w;
2857 tst_x = (float)gr_screen.max_w;
2858 tst_offset_total = (float)-w;
2859 tst_offset = (float)w;
2867 float diff = (tst_offset_total / 0.5f) * flFrametime;
2873 tst_offset -= fl_abs(diff);
2874 } else if(tst_mode == 2){
2877 tst_offset -= fl_abs(diff);
2881 gr_set_bitmap(tst_bitmap);
2882 gr_bitmap((int)tst_x, (int)tst_y);
2885 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2889 // if we passed the switch point
2890 if(tst_offset <= 0.0f){
2895 tst_stamp = timestamp(1000);
2896 tst_offset = fl_abs(tst_offset_total);
2907 void game_tst_mark(object *objp, ship *shipp)
2916 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2919 sip = &Ship_info[shipp->ship_info_index];
2926 tst_pos = objp->pos;
2927 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2933 extern void render_shields();
2935 void player_repair_frame(float frametime)
2937 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2939 for(idx=0;idx<MAX_PLAYERS;idx++){
2942 np = &Net_players[idx];
2944 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)){
2946 // don't rearm/repair if the player is dead or dying/departing
2947 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
2948 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
2953 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
2954 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
2960 #define NUM_FRAMES_TEST 300
2961 #define NUM_MIXED_SOUNDS 16
2962 void do_timing_test(float flFrametime)
2964 static int framecount = 0;
2965 static int test_running = 0;
2966 static float test_time = 0.0f;
2968 static int snds[NUM_MIXED_SOUNDS];
2971 if ( test_running ) {
2973 test_time += flFrametime;
2974 if ( framecount >= NUM_FRAMES_TEST ) {
2976 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
2977 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2982 if ( Test_begin == 1 ) {
2988 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2991 // start looping digital sounds
2992 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
2993 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3000 DCF(dcf_fov, "Change the field of view")
3003 dc_get_arg(ARG_FLOAT|ARG_NONE);
3004 if ( Dc_arg_type & ARG_NONE ) {
3005 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3006 dc_printf( "Zoom factor reset\n" );
3008 if ( Dc_arg_type & ARG_FLOAT ) {
3009 if (Dc_arg_float < 0.25f) {
3010 Viewer_zoom = 0.25f;
3011 dc_printf("Zoom factor pinned at 0.25.\n");
3012 } else if (Dc_arg_float > 1.25f) {
3013 Viewer_zoom = 1.25f;
3014 dc_printf("Zoom factor pinned at 1.25.\n");
3016 Viewer_zoom = Dc_arg_float;
3022 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3025 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3029 DCF(framerate_cap, "Sets the framerate cap")
3032 dc_get_arg(ARG_INT);
3033 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3034 Framerate_cap = Dc_arg_int;
3036 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3042 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3043 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3044 dc_printf("[n] must be from 1 to 120.\n");
3048 if ( Framerate_cap )
3049 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3051 dc_printf("There is no framerate cap currently active.\n");
3055 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3056 int Show_viewing_from_self = 0;
3058 void say_view_target()
3060 object *view_target;
3062 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3063 view_target = &Objects[Player_ai->target_objnum];
3065 view_target = Player_obj;
3067 if (Game_mode & GM_DEAD) {
3068 if (Player_ai->target_objnum != -1)
3069 view_target = &Objects[Player_ai->target_objnum];
3072 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3073 if (view_target != Player_obj){
3075 char *view_target_name = NULL;
3076 switch(Objects[Player_ai->target_objnum].type) {
3078 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3081 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3082 Viewer_mode &= ~VM_OTHER_SHIP;
3084 case OBJ_JUMP_NODE: {
3085 char jump_node_name[128];
3086 strcpy(jump_node_name, XSTR( "jump node", 184));
3087 view_target_name = jump_node_name;
3088 Viewer_mode &= ~VM_OTHER_SHIP;
3097 if ( view_target_name ) {
3098 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3099 Show_viewing_from_self = 1;
3102 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3103 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3104 Show_viewing_from_self = 1;
3106 if (Show_viewing_from_self)
3107 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3112 Last_view_target = view_target;
3116 float Game_hit_x = 0.0f;
3117 float Game_hit_y = 0.0f;
3119 // Reset at the beginning of each frame
3120 void game_whack_reset()
3126 // Apply a 2d whack to the player
3127 void game_whack_apply( float x, float y )
3129 // Do some force feedback
3130 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3136 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3139 // call to apply a "shudder"
3140 void game_shudder_apply(int time, float intensity)
3142 Game_shudder_time = timestamp(time);
3143 Game_shudder_total = time;
3144 Game_shudder_intensity = intensity;
3147 #define FF_SCALE 10000
3148 void apply_hud_shake(matrix *eye_orient)
3150 if (Viewer_obj == Player_obj) {
3151 physics_info *pi = &Player_obj->phys_info;
3159 // Make eye shake due to afterburner
3160 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3163 dtime = timestamp_until(pi->afterburner_decay);
3167 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3168 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3171 // Make eye shake due to engine wash
3173 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3176 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3177 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3179 // get the intensity
3180 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3184 vm_vec_rand_vec_quick(&rand_vec);
3187 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3191 // make hud shake due to shuddering
3192 if(Game_shudder_time != -1){
3193 // if the timestamp has elapsed
3194 if(timestamp_elapsed(Game_shudder_time)){
3195 Game_shudder_time = -1;
3197 // otherwise apply some shudder
3201 dtime = timestamp_until(Game_shudder_time);
3205 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));
3206 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));
3211 vm_angles_2_matrix(&tm, &tangles);
3212 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3213 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3214 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3215 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3220 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3222 // Player's velocity just before he blew up. Used to keep camera target moving.
3223 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3225 // Set eye_pos and eye_orient based on view mode.
3226 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3230 static int last_Viewer_mode = 0;
3231 static int last_Game_mode = 0;
3232 static int last_Viewer_objnum = -1;
3234 // This code is supposed to detect camera "cuts"... like going between
3237 // determine if we need to regenerate the nebula
3238 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3239 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3240 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3241 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3242 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3243 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3244 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3245 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3246 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3249 // regenerate the nebula
3253 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3254 //mprintf(( "************** Camera cut! ************\n" ));
3255 last_Viewer_mode = Viewer_mode;
3256 last_Game_mode = Game_mode;
3258 // Camera moved. Tell stars & debris to not do blurring.
3264 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3265 player_display_packlock_view();
3268 game_set_view_clip();
3270 if (Game_mode & GM_DEAD) {
3271 vector vec_to_deader, view_pos;
3274 Viewer_mode |= VM_DEAD_VIEW;
3276 if (Player_ai->target_objnum != -1) {
3277 int view_from_player = 1;
3279 if (Viewer_mode & VM_OTHER_SHIP) {
3280 // View from target.
3281 Viewer_obj = &Objects[Player_ai->target_objnum];
3283 last_Viewer_objnum = Player_ai->target_objnum;
3285 if ( Viewer_obj->type == OBJ_SHIP ) {
3286 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3287 view_from_player = 0;
3290 last_Viewer_objnum = -1;
3293 if ( view_from_player ) {
3294 // View target from player ship.
3296 *eye_pos = Player_obj->pos;
3297 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3298 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3301 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3303 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3304 dist += flFrametime * 16.0f;
3306 vm_vec_scale(&vec_to_deader, -dist);
3307 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3309 view_pos = Player_obj->pos;
3311 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3312 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3313 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3314 Dead_player_last_vel = Player_obj->phys_info.vel;
3315 //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));
3316 } else if (Player_ai->target_objnum != -1) {
3317 view_pos = Objects[Player_ai->target_objnum].pos;
3319 // Make camera follow explosion, but gradually slow down.
3320 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3321 view_pos = Player_obj->pos;
3322 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3323 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3326 *eye_pos = Dead_camera_pos;
3328 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3330 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3335 // if supernova shockwave
3336 if(supernova_camera_cut()){
3340 // call it dead view
3341 Viewer_mode |= VM_DEAD_VIEW;
3343 // set eye pos and orient
3344 supernova_set_view(eye_pos, eye_orient);
3346 // If already blown up, these other modes can override.
3347 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3348 Viewer_mode &= ~VM_DEAD_VIEW;
3350 Viewer_obj = Player_obj;
3352 if (Viewer_mode & VM_OTHER_SHIP) {
3353 if (Player_ai->target_objnum != -1){
3354 Viewer_obj = &Objects[Player_ai->target_objnum];
3355 last_Viewer_objnum = Player_ai->target_objnum;
3357 Viewer_mode &= ~VM_OTHER_SHIP;
3358 last_Viewer_objnum = -1;
3361 last_Viewer_objnum = -1;
3364 if (Viewer_mode & VM_EXTERNAL) {
3367 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3368 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3370 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3372 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3373 vm_vec_normalize(&eye_dir);
3374 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3377 // Modify the orientation based on head orientation.
3378 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3380 } else if ( Viewer_mode & VM_CHASE ) {
3383 if ( Viewer_obj->phys_info.speed < 0.1 )
3384 move_dir = Viewer_obj->orient.fvec;
3386 move_dir = Viewer_obj->phys_info.vel;
3387 vm_vec_normalize(&move_dir);
3390 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3391 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3392 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3393 vm_vec_normalize(&eye_dir);
3395 // JAS: I added the following code because if you slew up using
3396 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3397 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3398 // call because the up and the forward vector are the same. I fixed
3399 // it by adding in a fraction of the right vector all the time to the
3401 vector tmp_up = Viewer_obj->orient.uvec;
3402 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3404 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3407 // Modify the orientation based on head orientation.
3408 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3409 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3410 *eye_pos = Camera_pos;
3412 ship * shipp = &Ships[Player_obj->instance];
3414 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3415 vm_vec_normalize(&eye_dir);
3416 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3419 // get an eye position based upon the correct type of object
3420 switch(Viewer_obj->type){
3422 // make a call to get the eye point for the player object
3423 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3426 // make a call to get the eye point for the player object
3427 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3433 #ifdef JOHNS_DEBUG_CODE
3434 john_debug_stuff(&eye_pos, &eye_orient);
3440 apply_hud_shake(eye_orient);
3442 // setup neb2 rendering
3443 neb2_render_setup(eye_pos, eye_orient);
3447 extern void ai_debug_render_stuff();
3450 int Game_subspace_effect = 0;
3451 DCF_BOOL( subspace, Game_subspace_effect );
3453 // Does everything needed to render a frame
3454 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3458 g3_start_frame(game_zbuffer);
3459 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3461 // maybe offset the HUD (jitter stuff)
3462 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3463 HUD_set_offsets(Viewer_obj, !dont_offset);
3465 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3466 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3467 // must be done before ships are rendered
3468 if ( MULTIPLAYER_CLIENT ) {
3469 shield_point_multi_setup();
3472 if ( Game_subspace_effect ) {
3473 stars_draw(0,0,0,1);
3475 stars_draw(1,1,1,0);
3478 obj_render_all(obj_render);
3479 beam_render_all(); // render all beam weapons
3480 particle_render_all(); // render particles after everything else.
3481 trail_render_all(); // render missilie trails after everything else.
3482 mflash_render_all(); // render all muzzle flashes
3484 // Why do we not show the shield effect in these modes? Seems ok.
3485 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3489 // render nebula lightning
3492 // render local player nebula
3493 neb2_render_player();
3496 ai_debug_render_stuff();
3499 #ifndef RELEASE_REAL
3500 // game_framerate_check();
3504 extern void snd_spew_debug_info();
3505 snd_spew_debug_info();
3508 //================ END OF 3D RENDERING STUFF ====================
3512 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3513 hud_maybe_clear_head_area();
3514 anim_render_all(0, flFrametime);
3517 extern int Multi_display_netinfo;
3518 if(Multi_display_netinfo){
3519 extern void multi_display_netinfo();
3520 multi_display_netinfo();
3523 game_tst_frame_pre();
3526 do_timing_test(flFrametime);
3530 extern int OO_update_index;
3531 multi_rate_display(OO_update_index, 375, 0);
3536 extern void oo_display();
3543 //#define JOHNS_DEBUG_CODE 1
3545 #ifdef JOHNS_DEBUG_CODE
3546 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3548 //if ( keyd_pressed[KEY_LSHIFT] )
3550 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3552 model_subsystem *turret = tsys->system_info;
3554 if (turret->type == SUBSYSTEM_TURRET ) {
3556 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3558 ship_model_start(tobj);
3560 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3561 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3562 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3564 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3566 ship_model_stop(tobj);
3576 // following function for dumping frames for purposes of building trailers.
3579 // function to toggle state of dumping every frame into PCX when playing the game
3580 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3584 if ( Debug_dump_frames == 0 ) {
3586 Debug_dump_frames = 15;
3587 Debug_dump_trigger = 0;
3588 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3589 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3592 Debug_dump_frames = 0;
3593 Debug_dump_trigger = 0;
3594 gr_dump_frame_stop();
3595 dc_printf( "Frame dumping is now OFF\n" );
3601 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3605 if ( Debug_dump_frames == 0 ) {
3607 Debug_dump_frames = 15;
3608 Debug_dump_trigger = 1;
3609 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3610 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3613 Debug_dump_frames = 0;
3614 Debug_dump_trigger = 0;
3615 gr_dump_frame_stop();
3616 dc_printf( "Frame dumping is now OFF\n" );
3622 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3626 if ( Debug_dump_frames == 0 ) {
3628 Debug_dump_frames = 30;
3629 Debug_dump_trigger = 0;
3630 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3631 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3634 Debug_dump_frames = 0;
3635 Debug_dump_trigger = 0;
3636 gr_dump_frame_stop();
3637 dc_printf( "Frame dumping is now OFF\n" );
3643 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3647 if ( Debug_dump_frames == 0 ) {
3649 Debug_dump_frames = 30;
3650 Debug_dump_trigger = 1;
3651 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3652 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3655 Debug_dump_frames = 0;
3656 Debug_dump_trigger = 0;
3657 gr_dump_frame_stop();
3658 dc_printf( "Triggered frame dumping is now OFF\n" );
3664 void game_maybe_dump_frame()
3666 if ( !Debug_dump_frames ){
3670 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3677 Debug_dump_frame_num++;
3683 extern int Player_dead_state;
3685 // Flip the page and time how long it took.
3686 void game_flip_page_and_time_it()
3690 t1 = timer_get_fixed_seconds();
3692 t2 = timer_get_fixed_seconds();
3694 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3695 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3698 void game_simulation_frame()
3700 // blow ships up in multiplayer dogfight
3701 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){
3702 // blow up all non-player ships
3703 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3706 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3708 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)){
3709 moveup = GET_NEXT(moveup);
3712 shipp = &Ships[Objects[moveup->objnum].instance];
3713 sip = &Ship_info[shipp->ship_info_index];
3715 // only blow up small ships
3716 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3717 // function to simply explode a ship where it is currently at
3718 ship_self_destruct( &Objects[moveup->objnum] );
3721 moveup = GET_NEXT(moveup);
3727 // process AWACS stuff - do this first thing
3730 // single player, set Player hits_this_frame to 0
3731 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3732 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3733 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3737 supernova_process();
3738 if(supernova_active() >= 5){
3742 // fire targeting lasers now so that
3743 // 1 - created this frame
3744 // 2 - collide this frame
3745 // 3 - render this frame
3746 // 4 - ignored and deleted next frame
3747 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3749 ship_process_targeting_lasers();
3751 // do this here so that it works for multiplayer
3753 // get viewer direction
3754 int viewer_direction = PHYSICS_VIEWER_REAR;
3756 if(Viewer_mode == 0){
3757 viewer_direction = PHYSICS_VIEWER_FRONT;
3759 if(Viewer_mode & VM_PADLOCK_UP){
3760 viewer_direction = PHYSICS_VIEWER_UP;
3762 else if(Viewer_mode & VM_PADLOCK_REAR){
3763 viewer_direction = PHYSICS_VIEWER_REAR;
3765 else if(Viewer_mode & VM_PADLOCK_LEFT){
3766 viewer_direction = PHYSICS_VIEWER_LEFT;
3768 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3769 viewer_direction = PHYSICS_VIEWER_RIGHT;
3772 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3774 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3777 #define VM_PADLOCK_UP (1 << 7)
3778 #define VM_PADLOCK_REAR (1 << 8)
3779 #define VM_PADLOCK_LEFT (1 << 9)
3780 #define VM_PADLOCK_RIGHT (1 << 10)
3782 // evaluate mission departures and arrivals before we process all objects.
3783 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3785 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3786 // ships/wing packets.
3787 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3788 mission_parse_eval_stuff();
3791 // if we're an observer, move ourselves seperately from the standard physics
3792 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3793 obj_observer_move(flFrametime);
3796 // move all the objects now
3797 obj_move_all(flFrametime);
3799 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3800 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3801 // ship_check_cargo_all();
3802 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3803 mission_eval_goals();
3807 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3808 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3809 training_check_objectives();
3812 // do all interpolation now
3813 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3814 // client side processing of warping in effect stages
3815 multi_do_client_warp(flFrametime);
3817 // client side movement of an observer
3818 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3819 obj_observer_move(flFrametime);
3822 // move all objects - does interpolation now as well
3823 obj_move_all(flFrametime);
3826 // only process the message queue when the player is "in" the game
3827 if ( !Pre_player_entry ){
3828 message_queue_process(); // process any messages send to the player
3831 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3832 message_maybe_distort(); // maybe distort incoming message if comms damaged
3833 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3834 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3835 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3838 if(!(Game_mode & GM_STANDALONE_SERVER)){
3839 // process some stuff every frame (before frame is rendered)
3840 emp_process_local();
3842 hud_update_frame(); // update hud systems
3844 if (!physics_paused) {
3845 // Move particle system
3846 particle_move_all(flFrametime);
3848 // Move missile trails
3849 trail_move_all(flFrametime);
3851 // process muzzle flashes
3852 mflash_process_all();
3854 // Flash the gun flashes
3855 shipfx_flash_do_frame(flFrametime);
3857 shockwave_move_all(flFrametime); // update all the shockwaves
3860 // subspace missile strikes
3863 obj_snd_do_frame(); // update the object-linked persistant sounds
3864 game_maybe_update_sound_environment();
3865 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3867 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3869 if ( Game_subspace_effect ) {
3870 game_start_subspace_ambient_sound();
3876 // Maybe render and process the dead-popup
3877 void game_maybe_do_dead_popup(float frametime)
3879 if ( popupdead_is_active() ) {
3881 int choice = popupdead_do_frame(frametime);
3883 if ( Game_mode & GM_NORMAL ) {
3887 if(game_do_cd_mission_check(Game_current_mission_filename)){
3888 gameseq_post_event(GS_EVENT_ENTER_GAME);
3890 gameseq_post_event(GS_EVENT_MAIN_MENU);
3895 gameseq_post_event(GS_EVENT_END_GAME);
3900 if(game_do_cd_mission_check(Game_current_mission_filename)){
3901 gameseq_post_event(GS_EVENT_START_GAME);
3903 gameseq_post_event(GS_EVENT_MAIN_MENU);
3907 // this should only happen during a red alert mission
3910 Assert(The_mission.red_alert);
3911 if(!The_mission.red_alert){
3913 if(game_do_cd_mission_check(Game_current_mission_filename)){
3914 gameseq_post_event(GS_EVENT_START_GAME);
3916 gameseq_post_event(GS_EVENT_MAIN_MENU);
3921 // choose the previous mission
3922 mission_campaign_previous_mission();
3924 if(game_do_cd_mission_check(Game_current_mission_filename)){
3925 gameseq_post_event(GS_EVENT_START_GAME);
3927 gameseq_post_event(GS_EVENT_MAIN_MENU);
3938 case POPUPDEAD_DO_MAIN_HALL:
3939 multi_quit_game(PROMPT_NONE,-1);
3942 case POPUPDEAD_DO_RESPAWN:
3943 multi_respawn_normal();
3944 event_music_player_respawn();
3947 case POPUPDEAD_DO_OBSERVER:
3948 multi_respawn_observer();
3949 event_music_player_respawn_as_observer();
3958 if ( leave_popup ) {
3964 // returns true if player is actually in a game_play stats
3965 int game_actually_playing()
3969 state = gameseq_get_state();
3970 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
3976 // Draw the 2D HUD gauges
3977 void game_render_hud_2d()
3979 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
3983 HUD_render_2d(flFrametime);
3987 // Draw the 3D-dependant HUD gauges
3988 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
3990 g3_start_frame(0); // 0 = turn zbuffering off
3991 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3993 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
3994 HUD_render_3d(flFrametime);
3998 game_sunspot_process(flFrametime);
4000 // Diminish the palette effect
4001 game_flash_diminish(flFrametime);
4009 int actually_playing;
4010 fix total_time1, total_time2;
4011 fix render2_time1=0, render2_time2=0;
4012 fix render3_time1=0, render3_time2=0;
4013 fix flip_time1=0, flip_time2=0;
4014 fix clear_time1=0, clear_time2=0;
4020 if (Framerate_delay) {
4021 int start_time = timer_get_milliseconds();
4022 while (timer_get_milliseconds() < start_time + Framerate_delay)
4028 demo_do_frame_start();
4030 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4035 // start timing frame
4036 timing_frame_start();
4038 total_time1 = timer_get_fixed_seconds();
4040 // var to hold which state we are in
4041 actually_playing = game_actually_playing();
4043 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4044 if (!(Game_mode & GM_STANDALONE_SERVER)){
4045 Assert( OBJ_INDEX(Player_obj) >= 0 );
4049 if (Missiontime > Entry_delay_time){
4050 Pre_player_entry = 0;
4052 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4055 // Note: These are done even before the player enters, else buffers can overflow.
4056 if (! (Game_mode & GM_STANDALONE_SERVER)){
4060 shield_frame_init();
4062 if ( Player->control_mode != PCM_NORMAL )
4065 if ( !Pre_player_entry && actually_playing ) {
4066 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4068 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4069 game_process_keys();
4071 // don't read flying controls if we're playing a demo back
4072 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4073 read_player_controls( Player_obj, flFrametime);
4077 // if we're not the master, we may have to send the server-critical ship status button_info bits
4078 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4079 multi_maybe_send_ship_status();
4084 // Reset the whack stuff
4087 // These two lines must be outside of Pre_player_entry code,
4088 // otherwise too many lights are added.
4091 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4095 game_simulation_frame();
4097 // if not actually in a game play state, then return. This condition could only be true in
4098 // a multiplayer game.
4099 if ( !actually_playing ) {
4100 Assert( Game_mode & GM_MULTIPLAYER );
4104 if (!Pre_player_entry) {
4105 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4106 clear_time1 = timer_get_fixed_seconds();
4107 // clear the screen to black
4109 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4113 clear_time2 = timer_get_fixed_seconds();
4114 render3_time1 = timer_get_fixed_seconds();
4115 game_render_frame_setup(&eye_pos, &eye_orient);
4116 game_render_frame( &eye_pos, &eye_orient );
4118 // save the eye position and orientation
4119 if ( Game_mode & GM_MULTIPLAYER ) {
4120 Net_player->s_info.eye_pos = eye_pos;
4121 Net_player->s_info.eye_orient = eye_orient;
4124 hud_show_target_model();
4126 // check to see if we should display the death died popup
4127 if(Game_mode & GM_DEAD_BLEW_UP){
4128 if(Game_mode & GM_MULTIPLAYER){
4129 // catch the situation where we're supposed to be warping out on this transition
4130 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4131 gameseq_post_event(GS_EVENT_DEBRIEF);
4132 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4133 Player_died_popup_wait = -1;
4137 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4138 Player_died_popup_wait = -1;
4144 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4145 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4146 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4147 if(!popupdead_is_active()){
4151 Player_multi_died_check = -1;
4155 render3_time2 = timer_get_fixed_seconds();
4156 render2_time1 = timer_get_fixed_seconds();
4159 game_get_framerate();
4160 game_show_framerate();
4162 game_show_time_left();
4164 // Draw the 2D HUD gauges
4165 if(supernova_active() < 3){
4166 game_render_hud_2d();
4169 game_set_view_clip();
4171 // Draw 3D HUD gauges
4172 game_render_hud_3d(&eye_pos, &eye_orient);
4176 render2_time2 = timer_get_fixed_seconds();
4178 // maybe render and process the dead popup
4179 game_maybe_do_dead_popup(flFrametime);
4181 // start timing frame
4182 timing_frame_stop();
4183 // timing_display(30, 10);
4185 // If a regular popup is active, don't flip (popup code flips)
4186 if( !popup_running_state() ){
4187 flip_time1 = timer_get_fixed_seconds();
4188 game_flip_page_and_time_it();
4189 flip_time2 = timer_get_fixed_seconds();
4193 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4196 game_show_standalone_framerate();
4200 game_do_training_checks();
4203 // process lightning (nebula only)
4206 total_time2 = timer_get_fixed_seconds();
4208 // Got some timing numbers
4209 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4210 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4211 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4212 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4213 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4216 demo_do_frame_end();
4218 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4224 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4225 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4226 // died. This resulted in screwed up death sequences.
4228 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4229 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4230 static int timer_paused=0;
4231 static int stop_count,start_count;
4232 static int time_stopped,time_started;
4233 int saved_timestamp_ticker = -1;
4235 void game_reset_time()
4237 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4241 // Last_time = timer_get_fixed_seconds();
4247 void game_stop_time()
4249 if (timer_paused==0) {
4251 time = timer_get_fixed_seconds();
4252 // Save how much time progressed so far in the frame so we can
4253 // use it when we unpause.
4254 Last_delta_time = time - Last_time;
4256 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4257 if (Last_delta_time < 0) {
4258 #if defined(TIMER_TEST) && !defined(NDEBUG)
4259 Int3(); //get Matt!!!!
4261 Last_delta_time = 0;
4263 #if defined(TIMER_TEST) && !defined(NDEBUG)
4264 time_stopped = time;
4267 // Stop the timer_tick stuff...
4268 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4269 saved_timestamp_ticker = timestamp_ticker;
4273 #if defined(TIMER_TEST) && !defined(NDEBUG)
4278 void game_start_time()
4281 Assert(timer_paused >= 0);
4282 if (timer_paused==0) {
4284 time = timer_get_fixed_seconds();
4285 #if defined(TIMER_TEST) && !defined(NDEBUG)
4287 Int3(); //get Matt!!!!
4290 // Take current time, and set it backwards to account for time
4291 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4292 // will be correct when it goes to calculate the frametime next
4294 Last_time = time - Last_delta_time;
4295 #if defined(TIMER_TEST) && !defined(NDEBUG)
4296 time_started = time;
4299 // Restore the timer_tick stuff...
4300 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4301 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4302 timestamp_ticker = saved_timestamp_ticker;
4303 saved_timestamp_ticker = -1;
4306 #if defined(TIMER_TEST) && !defined(NDEBUG)
4312 void game_set_frametime(int state)
4315 float frame_cap_diff;
4317 thistime = timer_get_fixed_seconds();
4319 if ( Last_time == 0 )
4320 Frametime = F1_0 / 30;
4322 Frametime = thistime - Last_time;
4324 // Frametime = F1_0 / 30;
4326 fix debug_frametime = Frametime; // Just used to display frametime.
4328 // If player hasn't entered mission yet, make frame take 1/4 second.
4329 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4332 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4334 fix frame_speed = F1_0 / Debug_dump_frames;
4336 if (Frametime > frame_speed ){
4337 nprintf(("warning","slow frame: %x\n",Frametime));
4340 thistime = timer_get_fixed_seconds();
4341 Frametime = thistime - Last_time;
4342 } while (Frametime < frame_speed );
4344 Frametime = frame_speed;
4348 Assert( Framerate_cap > 0 );
4350 // Cap the framerate so it doesn't get too high.
4354 cap = F1_0/Framerate_cap;
4355 if (Frametime < cap) {
4356 thistime = cap - Frametime;
4357 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4358 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4360 thistime = timer_get_fixed_seconds();
4364 if((Game_mode & GM_STANDALONE_SERVER) &&
4365 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4367 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4368 Sleep((DWORD)(frame_cap_diff*1000));
4370 thistime += fl2f((frame_cap_diff));
4372 Frametime = thistime - Last_time;
4375 // If framerate is too low, cap it.
4376 if (Frametime > MAX_FRAMETIME) {
4378 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4380 // to remove warnings in release build
4381 debug_frametime = fl2f(flFrametime);
4383 Frametime = MAX_FRAMETIME;
4386 Frametime = fixmul(Frametime, Game_time_compression);
4388 Last_time = thistime;
4389 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4391 flFrametime = f2fl(Frametime);
4392 //if(!(Game_mode & GM_PLAYING_DEMO)){
4393 timestamp_inc(flFrametime);
4395 /* if ((Framecount > 0) && (Framecount < 10)) {
4396 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4401 // This is called from game_do_frame(), and from navmap_do_frame()
4402 void game_update_missiontime()
4404 // TODO JAS: Put in if and move this into game_set_frametime,
4405 // fix navmap to call game_stop/start_time
4406 //if ( !timer_paused )
4407 Missiontime += Frametime;
4410 void game_do_frame()
4412 game_set_frametime(GS_STATE_GAME_PLAY);
4413 game_update_missiontime();
4415 if (Game_mode & GM_STANDALONE_SERVER) {
4416 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4419 if ( game_single_step && (last_single_step == game_single_step) ) {
4420 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4421 while( key_checkch() == 0 )
4423 os_set_title( XSTR( "FreeSpace", 171) );
4424 Last_time = timer_get_fixed_seconds();
4427 last_single_step = game_single_step;
4429 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4430 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4434 Keep_mouse_centered = 0;
4435 monitor_update(); // Update monitor variables
4438 void multi_maybe_do_frame()
4440 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4445 int Joymouse_button_status = 0;
4447 // Flush all input devices
4455 Joymouse_button_status = 0;
4457 //mprintf(("Game flush!\n" ));
4460 // function for multiplayer only which calls game_do_state_common() when running the
4462 void game_do_dc_networking()
4464 Assert( Game_mode & GM_MULTIPLAYER );
4466 game_do_state_common( gameseq_get_state() );
4469 // Call this whenever in a loop, or when you need to check for a keystroke.
4470 int game_check_key()
4476 // convert keypad enter to normal enter
4477 if ((k & KEY_MASK) == KEY_PADENTER)
4478 k = (k & ~KEY_MASK) | KEY_ENTER;
4485 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4486 static int Demo_show_trailer_timestamp = 0;
4488 void demo_reset_trailer_timer()
4490 Demo_show_trailer_timestamp = timer_get_milliseconds();
4493 void demo_maybe_show_trailer(int k)
4496 // if key pressed, reset demo trailer timer
4498 demo_reset_trailer_timer();
4502 // if mouse moved, reset demo trailer timer
4505 mouse_get_delta(&dx, &dy);
4506 if ( (dx > 0) || (dy > 0) ) {
4507 demo_reset_trailer_timer();
4511 // if joystick has moved, reset demo trailer timer
4514 joy_get_delta(&dx, &dy);
4515 if ( (dx > 0) || (dy > 0) ) {
4516 demo_reset_trailer_timer();
4520 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4521 // the low-level code. Ugly, I know... but was the simplest and most
4524 // if 30 seconds since last demo trailer time reset, launch movie
4525 if ( os_foreground() ) {
4526 int now = timer_get_milliseconds();
4527 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4528 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4530 movie_play( NOX("fstrailer2.mve") );
4531 demo_reset_trailer_timer();
4539 // same as game_check_key(), except this is used while actually in the game. Since there
4540 // generally are differences between game control keys and general UI keys, makes sense to
4541 // have seperate functions for each case. If you are not checking a game control while in a
4542 // mission, you should probably be using game_check_key() instead.
4547 if (!os_foreground()) {
4552 // If we're in a single player game, pause it.
4553 if (!(Game_mode & GM_MULTIPLAYER)){
4554 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4555 game_process_pause_key();
4563 demo_maybe_show_trailer(k);
4566 // Move the mouse cursor with the joystick.
4567 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4568 // Move the mouse cursor with the joystick
4572 joy_get_pos( &jx, &jy, &jz, &jr );
4574 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4575 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4578 mouse_get_real_pos( &mx, &my );
4579 mouse_set_pos( mx+dx, my+dy );
4584 m = mouse_down(MOUSE_LEFT_BUTTON);
4586 if ( j != Joymouse_button_status ) {
4587 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4588 Joymouse_button_status = j;
4590 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4591 } else if ( (!j) && (m) ) {
4592 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4597 // if we should be ignoring keys because of some multiplayer situations
4598 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4602 // If a popup is running, don't process all the Fn keys
4603 if( popup_active() ) {
4607 state = gameseq_get_state();
4609 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4612 case KEY_DEBUGGED + KEY_BACKSP:
4617 launch_context_help();
4622 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4624 // don't allow f2 while warping out in multiplayer
4625 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4630 case GS_STATE_INITIAL_PLAYER_SELECT:
4631 case GS_STATE_OPTIONS_MENU:
4632 case GS_STATE_HUD_CONFIG:
4633 case GS_STATE_CONTROL_CONFIG:
4634 case GS_STATE_DEATH_DIED:
4635 case GS_STATE_DEATH_BLEW_UP:
4636 case GS_STATE_VIEW_MEDALS:
4640 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4647 // hotkey selection screen -- only valid from briefing and beyond.
4650 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) ) {
4651 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4657 case KEY_DEBUGGED + KEY_F3:
4658 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4661 case KEY_DEBUGGED + KEY_F4:
4662 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4666 if(Game_mode & GM_MULTIPLAYER){
4667 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4668 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4672 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4673 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4679 case KEY_ESC | KEY_SHIFTED:
4680 // make sure to quit properly out of multiplayer
4681 if(Game_mode & GM_MULTIPLAYER){
4682 multi_quit_game(PROMPT_NONE);
4685 gameseq_post_event( GS_EVENT_QUIT_GAME );
4690 case KEY_DEBUGGED + KEY_P:
4693 case KEY_PRINT_SCRN:
4700 sprintf( tmp_name, NOX("screen%02d"), counter );
4702 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4703 gr_print_screen(tmp_name);
4711 case KEY_SHIFTED | KEY_ENTER: {
4713 #if !defined(NDEBUG)
4715 if ( Game_mode & GM_NORMAL ){
4719 // if we're in multiplayer mode, do some special networking
4720 if(Game_mode & GM_MULTIPLAYER){
4721 debug_console(game_do_dc_networking);
4728 if ( Game_mode & GM_NORMAL )
4742 gameseq_post_event(GS_EVENT_QUIT_GAME);
4745 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4748 void camera_set_position( vector *pos )
4753 void camera_set_orient( matrix *orient )
4755 Camera_orient = *orient;
4758 void camera_set_velocity( vector *vel, int instantaneous )
4760 Camera_desired_velocity.x = 0.0f;
4761 Camera_desired_velocity.y = 0.0f;
4762 Camera_desired_velocity.z = 0.0f;
4764 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4765 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4766 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4768 if ( instantaneous ) {
4769 Camera_velocity = Camera_desired_velocity;
4777 vector new_vel, delta_pos;
4779 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4780 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4781 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4783 Camera_velocity = new_vel;
4785 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4787 vm_vec_add2( &Camera_pos, &delta_pos );
4789 float ot = Camera_time+0.0f;
4791 Camera_time += flFrametime;
4793 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4796 tmp.z = 4.739f; // always go this fast forward.
4798 // pick x and y velocities so they are always on a
4799 // circle with a 25 m radius.
4801 float tmp_angle = frand()*PI2;
4803 tmp.x = 22.0f * (float)sin(tmp_angle);
4804 tmp.y = -22.0f * (float)cos(tmp_angle);
4806 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4808 //mprintf(( "Changing velocity!\n" ));
4809 camera_set_velocity( &tmp, 0 );
4812 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4813 vector tmp = { 0.0f, 0.0f, 0.0f };
4814 camera_set_velocity( &tmp, 0 );
4819 void end_demo_campaign_do()
4821 #if defined(FS2_DEMO)
4822 // show upsell screens
4823 demo_upsell_show_screens();
4824 #elif defined(OEM_BUILD)
4825 // show oem upsell screens
4826 oem_upsell_show_screens();
4829 // drop into main hall
4830 gameseq_post_event( GS_EVENT_MAIN_MENU );
4833 // All code to process events. This is the only place
4834 // that you should change the state of the game.
4835 void game_process_event( int current_state, int event )
4837 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4840 case GS_EVENT_SIMULATOR_ROOM:
4841 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4844 case GS_EVENT_MAIN_MENU:
4845 gameseq_set_state(GS_STATE_MAIN_MENU);
4848 case GS_EVENT_OPTIONS_MENU:
4849 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4852 case GS_EVENT_BARRACKS_MENU:
4853 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4856 case GS_EVENT_TECH_MENU:
4857 gameseq_set_state(GS_STATE_TECH_MENU);
4860 case GS_EVENT_TRAINING_MENU:
4861 gameseq_set_state(GS_STATE_TRAINING_MENU);
4864 case GS_EVENT_START_GAME:
4865 Select_default_ship = 0;
4866 Player_multi_died_check = -1;
4867 gameseq_set_state(GS_STATE_CMD_BRIEF);
4870 case GS_EVENT_START_BRIEFING:
4871 gameseq_set_state(GS_STATE_BRIEFING);
4874 case GS_EVENT_DEBRIEF:
4875 // did we end the campaign in the main freespace 2 single player campaign?
4876 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4877 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4879 gameseq_set_state(GS_STATE_DEBRIEF);
4882 Player_multi_died_check = -1;
4885 case GS_EVENT_SHIP_SELECTION:
4886 gameseq_set_state( GS_STATE_SHIP_SELECT );
4889 case GS_EVENT_WEAPON_SELECTION:
4890 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4893 case GS_EVENT_ENTER_GAME:
4895 // maybe start recording a demo
4897 demo_start_record("test.fsd");
4901 if (Game_mode & GM_MULTIPLAYER) {
4902 // if we're respawning, make sure we change the view mode so that the hud shows up
4903 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4907 gameseq_set_state(GS_STATE_GAME_PLAY);
4909 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4912 Player_multi_died_check = -1;
4914 // clear multiplayer button info
4915 extern button_info Multi_ship_status_bi;
4916 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4918 Start_time = f2fl(timer_get_approx_seconds());
4920 mprintf(("Entering game at time = %7.3f\n", Start_time));
4924 case GS_EVENT_START_GAME_QUICK:
4925 Select_default_ship = 1;
4926 gameseq_post_event(GS_EVENT_ENTER_GAME);
4930 case GS_EVENT_END_GAME:
4931 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4932 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4933 gameseq_set_state(GS_STATE_MAIN_MENU);
4938 Player_multi_died_check = -1;
4941 case GS_EVENT_QUIT_GAME:
4942 main_hall_stop_music();
4943 main_hall_stop_ambient();
4944 gameseq_set_state(GS_STATE_QUIT_GAME);
4946 Player_multi_died_check = -1;
4949 case GS_EVENT_GAMEPLAY_HELP:
4950 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
4953 case GS_EVENT_PAUSE_GAME:
4954 gameseq_push_state(GS_STATE_GAME_PAUSED);
4957 case GS_EVENT_DEBUG_PAUSE_GAME:
4958 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
4961 case GS_EVENT_TRAINING_PAUSE:
4962 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
4965 case GS_EVENT_PREVIOUS_STATE:
4966 gameseq_pop_state();
4969 case GS_EVENT_TOGGLE_FULLSCREEN:
4970 #ifndef HARDWARE_ONLY
4972 if ( gr_screen.mode == GR_SOFTWARE ) {
4973 gr_init( GR_640, GR_DIRECTDRAW );
4974 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
4975 gr_init( GR_640, GR_SOFTWARE );
4981 case GS_EVENT_TOGGLE_GLIDE:
4983 if ( gr_screen.mode != GR_GLIDE ) {
4984 gr_init( GR_640, GR_GLIDE );
4986 gr_init( GR_640, GR_SOFTWARE );
4991 case GS_EVENT_LOAD_MISSION_MENU:
4992 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
4995 case GS_EVENT_MISSION_LOG_SCROLLBACK:
4996 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
4999 case GS_EVENT_HUD_CONFIG:
5000 gameseq_push_state( GS_STATE_HUD_CONFIG );
5003 case GS_EVENT_CONTROL_CONFIG:
5004 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5007 case GS_EVENT_DEATH_DIED:
5008 gameseq_set_state( GS_STATE_DEATH_DIED );
5011 case GS_EVENT_DEATH_BLEW_UP:
5012 if ( current_state == GS_STATE_DEATH_DIED ) {
5013 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5014 event_music_player_death();
5016 // multiplayer clients set their extra check here
5017 if(Game_mode & GM_MULTIPLAYER){
5018 // set the multi died absolute last chance check
5019 Player_multi_died_check = time(NULL);
5022 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5026 case GS_EVENT_NEW_CAMPAIGN:
5027 if (!mission_load_up_campaign()){
5028 readyroom_continue_campaign();
5031 Player_multi_died_check = -1;
5034 case GS_EVENT_CAMPAIGN_CHEAT:
5035 if (!mission_load_up_campaign()){
5037 // bash campaign value
5038 extern char Main_hall_campaign_cheat[512];
5041 // look for the mission
5042 for(idx=0; idx<Campaign.num_missions; idx++){
5043 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5044 Campaign.next_mission = idx;
5045 Campaign.prev_mission = idx - 1;
5052 readyroom_continue_campaign();
5055 Player_multi_died_check = -1;
5058 case GS_EVENT_CAMPAIGN_ROOM:
5059 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5062 case GS_EVENT_CMD_BRIEF:
5063 gameseq_set_state(GS_STATE_CMD_BRIEF);
5066 case GS_EVENT_RED_ALERT:
5067 gameseq_set_state(GS_STATE_RED_ALERT);
5070 case GS_EVENT_CREDITS:
5071 gameseq_set_state( GS_STATE_CREDITS );
5074 case GS_EVENT_VIEW_MEDALS:
5075 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5078 case GS_EVENT_SHOW_GOALS:
5079 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5082 case GS_EVENT_HOTKEY_SCREEN:
5083 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5086 // multiplayer stuff follow these comments
5088 case GS_EVENT_MULTI_JOIN_GAME:
5089 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5092 case GS_EVENT_MULTI_HOST_SETUP:
5093 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5096 case GS_EVENT_MULTI_CLIENT_SETUP:
5097 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5100 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5101 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5104 case GS_EVENT_MULTI_STD_WAIT:
5105 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5108 case GS_EVENT_STANDALONE_MAIN:
5109 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5112 case GS_EVENT_MULTI_PAUSE:
5113 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5116 case GS_EVENT_INGAME_PRE_JOIN:
5117 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5120 case GS_EVENT_EVENT_DEBUG:
5121 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5124 // Start a warpout where player automatically goes 70 no matter what
5125 // and can't cancel out of it.
5126 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5127 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5129 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5130 Player->saved_viewer_mode = Viewer_mode;
5131 Player->control_mode = PCM_WARPOUT_STAGE1;
5132 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5133 Warpout_time = 0.0f; // Start timer!
5136 case GS_EVENT_PLAYER_WARPOUT_START:
5137 if ( Player->control_mode != PCM_NORMAL ) {
5138 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5140 Player->saved_viewer_mode = Viewer_mode;
5141 Player->control_mode = PCM_WARPOUT_STAGE1;
5142 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5143 Warpout_time = 0.0f; // Start timer!
5144 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5148 case GS_EVENT_PLAYER_WARPOUT_STOP:
5149 if ( Player->control_mode != PCM_NORMAL ) {
5150 if ( !Warpout_forced ) { // cannot cancel forced warpout
5151 Player->control_mode = PCM_NORMAL;
5152 Viewer_mode = Player->saved_viewer_mode;
5153 hud_subspace_notify_abort();
5154 mprintf(( "Player put back to normal mode.\n" ));
5155 if ( Warpout_sound > -1 ) {
5156 snd_stop( Warpout_sound );
5163 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5164 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5165 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5166 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5168 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5169 shipfx_warpout_start( Player_obj );
5170 Player->control_mode = PCM_WARPOUT_STAGE2;
5171 Player->saved_viewer_mode = Viewer_mode;
5172 Viewer_mode |= VM_WARP_CHASE;
5174 vector tmp = Player_obj->pos;
5176 ship_get_eye( &tmp, &tmp_m, Player_obj );
5177 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5178 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5179 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5181 camera_set_position( &tmp );
5182 camera_set_orient( &Player_obj->orient );
5183 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5185 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5186 camera_set_velocity( &tmp_vel, 1);
5190 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5191 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5192 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5193 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5195 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5196 Player->control_mode = PCM_WARPOUT_STAGE3;
5200 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5201 mprintf(( "Player warped out. Going to debriefing!\n" ));
5202 Player->control_mode = PCM_NORMAL;
5203 Viewer_mode = Player->saved_viewer_mode;
5206 // we have a special debriefing screen for multiplayer furballs
5207 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5208 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5210 // do the normal debriefing for all other situations
5212 gameseq_post_event(GS_EVENT_DEBRIEF);
5216 case GS_EVENT_STANDALONE_POSTGAME:
5217 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5220 case GS_EVENT_INITIAL_PLAYER_SELECT:
5221 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5224 case GS_EVENT_GAME_INIT:
5225 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5226 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5228 // see if the command line option has been set to use the last pilot, and act acoordingly
5229 if( player_select_get_last_pilot() ) {
5230 // always enter the main menu -- do the automatic network startup stuff elsewhere
5231 // so that we still have valid checks for networking modes, etc.
5232 gameseq_set_state(GS_STATE_MAIN_MENU);
5234 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5239 case GS_EVENT_MULTI_MISSION_SYNC:
5240 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5243 case GS_EVENT_MULTI_START_GAME:
5244 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5247 case GS_EVENT_MULTI_HOST_OPTIONS:
5248 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5251 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5252 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5255 case GS_EVENT_TEAM_SELECT:
5256 gameseq_set_state(GS_STATE_TEAM_SELECT);
5259 case GS_EVENT_END_CAMPAIGN:
5260 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5263 case GS_EVENT_END_DEMO:
5264 gameseq_set_state(GS_STATE_END_DEMO);
5267 case GS_EVENT_LOOP_BRIEF:
5268 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5277 // Called when a state is being left.
5278 // The current state is still at old_state, but as soon as
5279 // this function leaves, then the current state will become
5280 // new state. You should never try to change the state
5281 // in here... if you think you need to, you probably really
5282 // need to post an event, not change the state.
5283 void game_leave_state( int old_state, int new_state )
5285 int end_mission = 1;
5287 switch (new_state) {
5288 case GS_STATE_GAME_PAUSED:
5289 case GS_STATE_DEBUG_PAUSED:
5290 case GS_STATE_OPTIONS_MENU:
5291 case GS_STATE_CONTROL_CONFIG:
5292 case GS_STATE_MISSION_LOG_SCROLLBACK:
5293 case GS_STATE_DEATH_DIED:
5294 case GS_STATE_SHOW_GOALS:
5295 case GS_STATE_HOTKEY_SCREEN:
5296 case GS_STATE_MULTI_PAUSED:
5297 case GS_STATE_TRAINING_PAUSED:
5298 case GS_STATE_EVENT_DEBUG:
5299 case GS_STATE_GAMEPLAY_HELP:
5300 end_mission = 0; // these events shouldn't end a mission
5304 switch (old_state) {
5305 case GS_STATE_BRIEFING:
5306 brief_stop_voices();
5307 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5308 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5309 && (new_state != GS_STATE_TEAM_SELECT) ){
5310 common_select_close();
5311 if ( new_state == GS_STATE_MAIN_MENU ) {
5312 freespace_stop_mission();
5316 // COMMAND LINE OPTION
5317 if (Cmdline_multi_stream_chat_to_file){
5318 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5319 cfclose(Multi_chat_stream);
5323 case GS_STATE_DEBRIEF:
5324 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5329 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5330 multi_df_debrief_close();
5333 case GS_STATE_LOAD_MISSION_MENU:
5334 mission_load_menu_close();
5337 case GS_STATE_SIMULATOR_ROOM:
5341 case GS_STATE_CAMPAIGN_ROOM:
5342 campaign_room_close();
5345 case GS_STATE_CMD_BRIEF:
5346 if (new_state == GS_STATE_OPTIONS_MENU) {
5351 if (new_state == GS_STATE_MAIN_MENU)
5352 freespace_stop_mission();
5357 case GS_STATE_RED_ALERT:
5361 case GS_STATE_SHIP_SELECT:
5362 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5363 new_state != GS_STATE_HOTKEY_SCREEN &&
5364 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5365 common_select_close();
5366 if ( new_state == GS_STATE_MAIN_MENU ) {
5367 freespace_stop_mission();
5372 case GS_STATE_WEAPON_SELECT:
5373 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5374 new_state != GS_STATE_HOTKEY_SCREEN &&
5375 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5376 common_select_close();
5377 if ( new_state == GS_STATE_MAIN_MENU ) {
5378 freespace_stop_mission();
5383 case GS_STATE_TEAM_SELECT:
5384 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5385 new_state != GS_STATE_HOTKEY_SCREEN &&
5386 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5387 common_select_close();
5388 if ( new_state == GS_STATE_MAIN_MENU ) {
5389 freespace_stop_mission();
5394 case GS_STATE_MAIN_MENU:
5395 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5402 case GS_STATE_OPTIONS_MENU:
5403 //game_start_time();
5404 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5405 multi_join_clear_game_list();
5407 options_menu_close();
5410 case GS_STATE_BARRACKS_MENU:
5411 if(new_state != GS_STATE_VIEW_MEDALS){
5416 case GS_STATE_MISSION_LOG_SCROLLBACK:
5417 hud_scrollback_close();
5420 case GS_STATE_TRAINING_MENU:
5421 training_menu_close();
5424 case GS_STATE_GAME_PLAY:
5425 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5426 player_save_target_and_weapon_link_prefs();
5427 game_stop_looped_sounds();
5430 sound_env_disable();
5431 joy_ff_stop_effects();
5433 // stop game time under certain conditions
5434 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5439 // shut down any recording or playing demos
5444 // when in multiplayer and going back to the main menu, send a leave game packet
5445 // right away (before calling stop mission). stop_mission was taking to long to
5446 // close mission down and I want people to get notified ASAP.
5447 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5448 multi_quit_game(PROMPT_NONE);
5451 freespace_stop_mission();
5452 Game_time_compression = F1_0;
5456 case GS_STATE_TECH_MENU:
5460 case GS_STATE_TRAINING_PAUSED:
5461 Training_num_lines = 0;
5462 // fall through to GS_STATE_GAME_PAUSED
5464 case GS_STATE_GAME_PAUSED:
5466 if ( end_mission ) {
5471 case GS_STATE_DEBUG_PAUSED:
5474 pause_debug_close();
5478 case GS_STATE_HUD_CONFIG:
5482 // join/start a game
5483 case GS_STATE_MULTI_JOIN_GAME:
5484 if(new_state != GS_STATE_OPTIONS_MENU){
5485 multi_join_game_close();
5489 case GS_STATE_MULTI_HOST_SETUP:
5490 case GS_STATE_MULTI_CLIENT_SETUP:
5491 // if this is just the host going into the options screen, don't do anything
5492 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5496 // close down the proper state
5497 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5498 multi_create_game_close();
5500 multi_game_client_setup_close();
5503 // COMMAND LINE OPTION
5504 if (Cmdline_multi_stream_chat_to_file){
5505 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5506 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5507 cfclose(Multi_chat_stream);
5512 case GS_STATE_CONTROL_CONFIG:
5513 control_config_close();
5516 case GS_STATE_DEATH_DIED:
5517 Game_mode &= ~GM_DEAD_DIED;
5519 // early end while respawning or blowing up in a multiplayer game
5520 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5522 freespace_stop_mission();
5526 case GS_STATE_DEATH_BLEW_UP:
5527 Game_mode &= ~GM_DEAD_BLEW_UP;
5529 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5530 // to determine if I should do anything.
5531 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5533 freespace_stop_mission();
5536 // if we are not respawing as an observer or as a player, our new state will not
5537 // be gameplay state.
5538 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5539 game_stop_time(); // hasn't been called yet!!
5540 freespace_stop_mission();
5546 case GS_STATE_CREDITS:
5550 case GS_STATE_VIEW_MEDALS:
5554 case GS_STATE_SHOW_GOALS:
5555 mission_show_goals_close();
5558 case GS_STATE_HOTKEY_SCREEN:
5559 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5560 mission_hotkey_close();
5564 case GS_STATE_MULTI_MISSION_SYNC:
5565 // if we're moving into the options menu, don't do anything
5566 if(new_state == GS_STATE_OPTIONS_MENU){
5570 Assert( Game_mode & GM_MULTIPLAYER );
5572 if ( new_state == GS_STATE_GAME_PLAY ){
5573 // palette_restore_palette();
5575 // change a couple of flags to indicate our state!!!
5576 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5577 send_netplayer_update_packet();
5579 // set the game mode
5580 Game_mode |= GM_IN_MISSION;
5584 case GS_STATE_VIEW_CUTSCENES:
5585 cutscenes_screen_close();
5588 case GS_STATE_MULTI_STD_WAIT:
5589 multi_standalone_wait_close();
5592 case GS_STATE_STANDALONE_MAIN:
5593 standalone_main_close();
5594 if(new_state == GS_STATE_MULTI_STD_WAIT){
5595 init_multiplayer_stats();
5599 case GS_STATE_MULTI_PAUSED:
5600 // if ( end_mission ){
5605 case GS_STATE_INGAME_PRE_JOIN:
5606 multi_ingame_select_close();
5609 case GS_STATE_STANDALONE_POSTGAME:
5610 multi_standalone_postgame_close();
5613 case GS_STATE_INITIAL_PLAYER_SELECT:
5614 player_select_close();
5617 case GS_STATE_MULTI_START_GAME:
5618 multi_start_game_close();
5621 case GS_STATE_MULTI_HOST_OPTIONS:
5622 multi_host_options_close();
5625 case GS_STATE_END_OF_CAMPAIGN:
5626 mission_campaign_end_close();
5629 case GS_STATE_LOOP_BRIEF:
5635 // Called when a state is being entered.
5636 // The current state is set to the state we're entering at
5637 // this point, and old_state is set to the state we're coming
5638 // from. You should never try to change the state
5639 // in here... if you think you need to, you probably really
5640 // need to post an event, not change the state.
5642 void game_enter_state( int old_state, int new_state )
5644 switch (new_state) {
5645 case GS_STATE_MAIN_MENU:
5646 // in multiplayer mode, be sure that we are not doing networking anymore.
5647 if ( Game_mode & GM_MULTIPLAYER ) {
5648 Assert( Net_player != NULL );
5649 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5652 Game_time_compression = F1_0;
5654 // determine which ship this guy is currently based on
5655 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5658 if (Player->on_bastion) {
5666 case GS_STATE_BRIEFING:
5667 main_hall_stop_music();
5668 main_hall_stop_ambient();
5670 if (Game_mode & GM_NORMAL) {
5671 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5672 // MWA: or from options or hotkey screens
5673 // JH: or if the command brief state already did this
5674 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5675 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5676 && (old_state != GS_STATE_CMD_BRIEF) ) {
5677 if ( !game_start_mission() ) // this should put us into a new state on failure!
5681 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5682 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5683 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5685 Game_time_compression = F1_0;
5687 if ( red_alert_mission() ) {
5688 gameseq_post_event(GS_EVENT_RED_ALERT);
5695 case GS_STATE_DEBRIEF:
5696 game_stop_looped_sounds();
5697 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5698 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5703 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5704 multi_df_debrief_init();
5707 case GS_STATE_LOAD_MISSION_MENU:
5708 mission_load_menu_init();
5711 case GS_STATE_SIMULATOR_ROOM:
5715 case GS_STATE_CAMPAIGN_ROOM:
5716 campaign_room_init();
5719 case GS_STATE_RED_ALERT:
5720 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5724 case GS_STATE_CMD_BRIEF: {
5725 int team_num = 0; // team number used as index for which cmd brief to use.
5727 if (old_state == GS_STATE_OPTIONS_MENU) {
5731 main_hall_stop_music();
5732 main_hall_stop_ambient();
5734 if (Game_mode & GM_NORMAL) {
5735 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5736 // MWA: or from options or hotkey screens
5737 // JH: or if the command brief state already did this
5738 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5739 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5740 if ( !game_start_mission() ) // this should put us into a new state on failure!
5745 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5746 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5747 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5749 cmd_brief_init(team_num);
5755 case GS_STATE_SHIP_SELECT:
5759 case GS_STATE_WEAPON_SELECT:
5760 weapon_select_init();
5763 case GS_STATE_TEAM_SELECT:
5767 case GS_STATE_GAME_PAUSED:
5772 case GS_STATE_DEBUG_PAUSED:
5773 // game_stop_time();
5774 // os_set_title("FreeSpace - PAUSED");
5777 case GS_STATE_TRAINING_PAUSED:
5784 case GS_STATE_OPTIONS_MENU:
5786 options_menu_init();
5789 case GS_STATE_GAME_PLAY:
5790 // coming from the gameplay state or the main menu, we might need to load the mission
5791 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5792 if ( !game_start_mission() ) // this should put us into a new state.
5797 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5798 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5799 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5800 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5801 (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) ) {
5802 // JAS: Used to do all paging here.
5806 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5810 main_hall_stop_music();
5811 main_hall_stop_ambient();
5812 event_music_first_pattern(); // start the first pattern
5815 // special code that restores player ship selection and weapons loadout when doing a quick start
5816 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5817 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5818 wss_direct_restore_loadout();
5822 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5823 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5824 event_music_first_pattern(); // start the first pattern
5827 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5828 event_music_first_pattern(); // start the first pattern
5830 player_restore_target_and_weapon_link_prefs();
5832 Game_mode |= GM_IN_MISSION;
5835 // required to truely make mouse deltas zeroed in debug mouse code
5836 void mouse_force_pos(int x, int y);
5837 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5842 // only start time if in single player, or coming from multi wait state
5845 (Game_mode & GM_NORMAL) &&
5846 (old_state != GS_STATE_VIEW_CUTSCENES)
5848 (Game_mode & GM_MULTIPLAYER) && (
5849 (old_state == GS_STATE_MULTI_PAUSED) ||
5850 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5856 // when coming from the multi paused state, reset the timestamps
5857 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5858 multi_reset_timestamps();
5861 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5862 // initialize all object update details
5863 multi_oo_gameplay_init();
5866 // under certain circumstances, the server should reset the object update rate limiting stuff
5867 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5868 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5870 // reinitialize the rate limiting system for all clients
5871 multi_oo_rate_init_all();
5874 // multiplayer clients should always re-initialize their control info rate limiting system
5875 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5876 multi_oo_rate_init_all();
5880 if(Game_mode & GM_MULTIPLAYER){
5881 multi_ping_reset_players();
5884 Game_subspace_effect = 0;
5885 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5886 Game_subspace_effect = 1;
5887 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5888 game_start_subspace_ambient_sound();
5892 sound_env_set(&Game_sound_env);
5893 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5895 // clear multiplayer button info i
5896 extern button_info Multi_ship_status_bi;
5897 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5900 case GS_STATE_HUD_CONFIG:
5904 case GS_STATE_MULTI_JOIN_GAME:
5905 multi_join_clear_game_list();
5907 if (old_state != GS_STATE_OPTIONS_MENU) {
5908 multi_join_game_init();
5913 case GS_STATE_MULTI_HOST_SETUP:
5914 // don't reinitialize if we're coming back from the host options screen
5915 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5916 multi_create_game_init();
5921 case GS_STATE_MULTI_CLIENT_SETUP:
5922 if (old_state != GS_STATE_OPTIONS_MENU) {
5923 multi_game_client_setup_init();
5928 case GS_STATE_CONTROL_CONFIG:
5929 control_config_init();
5932 case GS_STATE_TECH_MENU:
5936 case GS_STATE_BARRACKS_MENU:
5937 if(old_state != GS_STATE_VIEW_MEDALS){
5942 case GS_STATE_MISSION_LOG_SCROLLBACK:
5943 hud_scrollback_init();
5946 case GS_STATE_DEATH_DIED:
5947 Player_died_time = timestamp(10);
5949 if(!(Game_mode & GM_MULTIPLAYER)){
5950 player_show_death_message();
5952 Game_mode |= GM_DEAD_DIED;
5955 case GS_STATE_DEATH_BLEW_UP:
5956 if ( !popupdead_is_active() ) {
5957 Player_ai->target_objnum = -1;
5960 // stop any local EMP effect
5963 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
5964 Game_mode |= GM_DEAD_BLEW_UP;
5965 Show_viewing_from_self = 0;
5967 // timestamp how long we should wait before displaying the died popup
5968 if ( !popupdead_is_active() ) {
5969 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
5973 case GS_STATE_GAMEPLAY_HELP:
5974 gameplay_help_init();
5977 case GS_STATE_CREDITS:
5978 main_hall_stop_music();
5979 main_hall_stop_ambient();
5983 case GS_STATE_VIEW_MEDALS:
5984 medal_main_init(Player);
5987 case GS_STATE_SHOW_GOALS:
5988 mission_show_goals_init();
5991 case GS_STATE_HOTKEY_SCREEN:
5992 mission_hotkey_init();
5995 case GS_STATE_MULTI_MISSION_SYNC:
5996 // if we're coming from the options screen, don't do any
5997 if(old_state == GS_STATE_OPTIONS_MENU){
6001 switch(Multi_sync_mode){
6002 case MULTI_SYNC_PRE_BRIEFING:
6003 // if moving from game forming to the team select state
6006 case MULTI_SYNC_POST_BRIEFING:
6007 // if moving from briefing into the mission itself
6010 // tell everyone that we're now loading data
6011 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6012 send_netplayer_update_packet();
6014 // JAS: Used to do all paging here!!!!
6016 Net_player->state = NETPLAYER_STATE_WAITING;
6017 send_netplayer_update_packet();
6019 Game_time_compression = F1_0;
6021 case MULTI_SYNC_INGAME:
6027 case GS_STATE_VIEW_CUTSCENES:
6028 cutscenes_screen_init();
6031 case GS_STATE_MULTI_STD_WAIT:
6032 multi_standalone_wait_init();
6035 case GS_STATE_STANDALONE_MAIN:
6036 // don't initialize if we're coming from one of these 2 states unless there are no
6037 // players left (reset situation)
6038 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6039 standalone_main_init();
6043 case GS_STATE_MULTI_PAUSED:
6047 case GS_STATE_INGAME_PRE_JOIN:
6048 multi_ingame_select_init();
6051 case GS_STATE_STANDALONE_POSTGAME:
6052 multi_standalone_postgame_init();
6055 case GS_STATE_INITIAL_PLAYER_SELECT:
6056 player_select_init();
6059 case GS_STATE_MULTI_START_GAME:
6060 multi_start_game_init();
6063 case GS_STATE_MULTI_HOST_OPTIONS:
6064 multi_host_options_init();
6067 case GS_STATE_END_OF_CAMPAIGN:
6068 mission_campaign_end_init();
6071 case GS_STATE_LOOP_BRIEF:
6078 // do stuff that may need to be done regardless of state
6079 void game_do_state_common(int state,int no_networking)
6081 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6082 snd_do_frame(); // update sound system
6083 event_music_do_frame(); // music needs to play across many states
6085 multi_log_process();
6087 if (no_networking) {
6091 // maybe do a multiplayer frame based on game mode and state type
6092 if (Game_mode & GM_MULTIPLAYER) {
6094 case GS_STATE_OPTIONS_MENU:
6095 case GS_STATE_GAMEPLAY_HELP:
6096 case GS_STATE_HOTKEY_SCREEN:
6097 case GS_STATE_HUD_CONFIG:
6098 case GS_STATE_CONTROL_CONFIG:
6099 case GS_STATE_MISSION_LOG_SCROLLBACK:
6100 case GS_STATE_SHOW_GOALS:
6101 case GS_STATE_VIEW_CUTSCENES:
6102 case GS_STATE_EVENT_DEBUG:
6103 multi_maybe_do_frame();
6107 game_do_networking();
6111 // Called once a frame.
6112 // You should never try to change the state
6113 // in here... if you think you need to, you probably really
6114 // need to post an event, not change the state.
6115 int Game_do_state_should_skip = 0;
6116 void game_do_state(int state)
6118 // always lets the do_state_common() function determine if the state should be skipped
6119 Game_do_state_should_skip = 0;
6121 // legal to set the should skip state anywhere in this function
6122 game_do_state_common(state); // do stuff that may need to be done regardless of state
6124 if(Game_do_state_should_skip){
6129 case GS_STATE_MAIN_MENU:
6130 game_set_frametime(GS_STATE_MAIN_MENU);
6131 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6134 main_hall_do(flFrametime);
6138 case GS_STATE_OPTIONS_MENU:
6139 game_set_frametime(GS_STATE_OPTIONS_MENU);
6140 options_menu_do_frame(flFrametime);
6143 case GS_STATE_BARRACKS_MENU:
6144 game_set_frametime(GS_STATE_BARRACKS_MENU);
6145 barracks_do_frame(flFrametime);
6148 case GS_STATE_TRAINING_MENU:
6149 game_set_frametime(GS_STATE_TRAINING_MENU);
6150 training_menu_do_frame(flFrametime);
6153 case GS_STATE_TECH_MENU:
6154 game_set_frametime(GS_STATE_TECH_MENU);
6155 techroom_do_frame(flFrametime);
6158 case GS_STATE_GAMEPLAY_HELP:
6159 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6160 gameplay_help_do_frame(flFrametime);
6163 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6167 case GS_STATE_GAME_PAUSED:
6171 case GS_STATE_DEBUG_PAUSED:
6173 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6178 case GS_STATE_TRAINING_PAUSED:
6179 game_training_pause_do();
6182 case GS_STATE_LOAD_MISSION_MENU:
6183 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6184 mission_load_menu_do();
6187 case GS_STATE_BRIEFING:
6188 game_set_frametime(GS_STATE_BRIEFING);
6189 brief_do_frame(flFrametime);
6192 case GS_STATE_DEBRIEF:
6193 game_set_frametime(GS_STATE_DEBRIEF);
6194 debrief_do_frame(flFrametime);
6197 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6198 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6199 multi_df_debrief_do();
6202 case GS_STATE_SHIP_SELECT:
6203 game_set_frametime(GS_STATE_SHIP_SELECT);
6204 ship_select_do(flFrametime);
6207 case GS_STATE_WEAPON_SELECT:
6208 game_set_frametime(GS_STATE_WEAPON_SELECT);
6209 weapon_select_do(flFrametime);
6212 case GS_STATE_MISSION_LOG_SCROLLBACK:
6213 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6214 hud_scrollback_do_frame(flFrametime);
6217 case GS_STATE_HUD_CONFIG:
6218 game_set_frametime(GS_STATE_HUD_CONFIG);
6219 hud_config_do_frame(flFrametime);
6222 case GS_STATE_MULTI_JOIN_GAME:
6223 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6224 multi_join_game_do_frame();
6227 case GS_STATE_MULTI_HOST_SETUP:
6228 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6229 multi_create_game_do();
6232 case GS_STATE_MULTI_CLIENT_SETUP:
6233 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6234 multi_game_client_setup_do_frame();
6237 case GS_STATE_CONTROL_CONFIG:
6238 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6239 control_config_do_frame(flFrametime);
6242 case GS_STATE_DEATH_DIED:
6246 case GS_STATE_DEATH_BLEW_UP:
6250 case GS_STATE_SIMULATOR_ROOM:
6251 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6252 sim_room_do_frame(flFrametime);
6255 case GS_STATE_CAMPAIGN_ROOM:
6256 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6257 campaign_room_do_frame(flFrametime);
6260 case GS_STATE_RED_ALERT:
6261 game_set_frametime(GS_STATE_RED_ALERT);
6262 red_alert_do_frame(flFrametime);
6265 case GS_STATE_CMD_BRIEF:
6266 game_set_frametime(GS_STATE_CMD_BRIEF);
6267 cmd_brief_do_frame(flFrametime);
6270 case GS_STATE_CREDITS:
6271 game_set_frametime(GS_STATE_CREDITS);
6272 credits_do_frame(flFrametime);
6275 case GS_STATE_VIEW_MEDALS:
6276 game_set_frametime(GS_STATE_VIEW_MEDALS);
6280 case GS_STATE_SHOW_GOALS:
6281 game_set_frametime(GS_STATE_SHOW_GOALS);
6282 mission_show_goals_do_frame(flFrametime);
6285 case GS_STATE_HOTKEY_SCREEN:
6286 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6287 mission_hotkey_do_frame(flFrametime);
6290 case GS_STATE_VIEW_CUTSCENES:
6291 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6292 cutscenes_screen_do_frame();
6295 case GS_STATE_MULTI_STD_WAIT:
6296 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6297 multi_standalone_wait_do();
6300 case GS_STATE_STANDALONE_MAIN:
6301 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6302 standalone_main_do();
6305 case GS_STATE_MULTI_PAUSED:
6306 game_set_frametime(GS_STATE_MULTI_PAUSED);
6310 case GS_STATE_TEAM_SELECT:
6311 game_set_frametime(GS_STATE_TEAM_SELECT);
6315 case GS_STATE_INGAME_PRE_JOIN:
6316 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6317 multi_ingame_select_do();
6320 case GS_STATE_EVENT_DEBUG:
6322 game_set_frametime(GS_STATE_EVENT_DEBUG);
6323 game_show_event_debug(flFrametime);
6327 case GS_STATE_STANDALONE_POSTGAME:
6328 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6329 multi_standalone_postgame_do();
6332 case GS_STATE_INITIAL_PLAYER_SELECT:
6333 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6337 case GS_STATE_MULTI_MISSION_SYNC:
6338 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6342 case GS_STATE_MULTI_START_GAME:
6343 game_set_frametime(GS_STATE_MULTI_START_GAME);
6344 multi_start_game_do();
6347 case GS_STATE_MULTI_HOST_OPTIONS:
6348 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6349 multi_host_options_do();
6352 case GS_STATE_END_OF_CAMPAIGN:
6353 mission_campaign_end_do();
6356 case GS_STATE_END_DEMO:
6357 game_set_frametime(GS_STATE_END_DEMO);
6358 end_demo_campaign_do();
6361 case GS_STATE_LOOP_BRIEF:
6362 game_set_frametime(GS_STATE_LOOP_BRIEF);
6366 } // end switch(gs_current_state)
6370 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6371 int game_do_ram_check(int ram_in_bytes)
6373 if ( ram_in_bytes < 30*1024*1024 ) {
6374 int allowed_to_run = 1;
6375 if ( ram_in_bytes < 25*1024*1024 ) {
6380 int Freespace_total_ram_MB;
6381 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6383 if ( allowed_to_run ) {
6385 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);
6388 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6389 if ( msgbox_rval == IDCANCEL ) {
6394 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);
6395 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6403 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6404 // If so, copy it over and remove the update directory.
6405 void game_maybe_update_launcher(char *exe_dir)
6407 char src_filename[MAX_PATH];
6408 char dest_filename[MAX_PATH];
6410 strcpy(src_filename, exe_dir);
6411 strcat(src_filename, NOX("\\update\\freespace.exe"));
6413 strcpy(dest_filename, exe_dir);
6414 strcat(dest_filename, NOX("\\freespace.exe"));
6416 // see if src_filename exists
6418 fp = fopen(src_filename, "rb");
6424 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6426 // copy updated freespace.exe to freespace exe dir
6427 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6428 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 );
6432 // delete the file in the update directory
6433 DeleteFile(src_filename);
6435 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6436 char update_dir[MAX_PATH];
6437 strcpy(update_dir, exe_dir);
6438 strcat(update_dir, NOX("\\update"));
6439 RemoveDirectory(update_dir);
6442 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6446 int sub_total_destroyed = 0;
6450 // get the total for all his children
6451 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6452 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6455 // find the # of faces for this _individual_ object
6456 total = submodel_get_num_polys(model_num, sm);
6457 if(strstr(pm->submodel[sm].name, "-destroyed")){
6458 sub_total_destroyed = total;
6462 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6465 *out_total += total + sub_total;
6466 *out_destroyed_total += sub_total_destroyed;
6469 #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);
6470 void game_spew_pof_info()
6472 char *pof_list[1000];
6475 int idx, model_num, i, j;
6477 int total, root_total, model_total, destroyed_total, counted;
6481 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6483 // spew info on all the pofs
6489 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6494 for(idx=0; idx<num_files; idx++, counted++){
6495 sprintf(str, "%s.pof", pof_list[idx]);
6496 model_num = model_load(str, 0, NULL);
6498 pm = model_get(model_num);
6500 // if we have a real model
6505 // go through and print all raw submodels
6506 cfputs("RAW\n", out);
6509 for (i=0; i<pm->n_models; i++) {
6510 total = submodel_get_num_polys(model_num, i);
6512 model_total += total;
6513 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6516 sprintf(str, "Model total %d\n", model_total);
6519 // now go through and do it by LOD
6520 cfputs("BY LOD\n\n", out);
6521 for(i=0; i<pm->n_detail_levels; i++){
6522 sprintf(str, "LOD %d\n", i);
6526 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6528 destroyed_total = 0;
6529 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6530 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6533 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6536 sprintf(str, "TOTAL: %d\n", total + root_total);
6538 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6540 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6543 cfputs("------------------------------------------------------------------------\n\n", out);
6547 if(counted >= MAX_POLYGON_MODELS - 5){
6560 game_spew_pof_info();
6563 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6567 // Don't let more than one instance of Freespace run.
6568 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6570 SetForegroundWindow(hwnd);
6574 // Find out how much RAM is on this machine
6576 ms.dwLength = sizeof(MEMORYSTATUS);
6577 GlobalMemoryStatus(&ms);
6578 Freespace_total_ram = ms.dwTotalPhys;
6580 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6584 if ( ms.dwTotalVirtual < 1024 ) {
6585 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6589 if (!vm_init(24*1024*1024)) {
6590 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 );
6594 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6596 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);
6603 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6604 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6605 seem worth bothering with.
6609 lResult = RegOpenKeyEx(
6610 HKEY_LOCAL_MACHINE, // Where it is
6611 "Software\\Microsoft\\DirectX", // name of key
6612 NULL, // DWORD reserved
6613 KEY_QUERY_VALUE, // Allows all changes
6614 &hKey // Location to store key
6617 if (lResult == ERROR_SUCCESS) {
6619 DWORD dwType, dwLen;
6622 lResult = RegQueryValueEx(
6623 hKey, // Handle to key
6624 "Version", // The values name
6625 NULL, // DWORD reserved
6626 &dwType, // What kind it is
6627 (ubyte *) version, // value to set
6628 &dwLen // How many bytes to set
6631 if (lResult == ERROR_SUCCESS) {
6632 dx_version = atoi(strstr(version, ".") + 1);
6636 DWORD dwType, dwLen;
6639 lResult = RegQueryValueEx(
6640 hKey, // Handle to key
6641 "InstalledVersion", // The values name
6642 NULL, // DWORD reserved
6643 &dwType, // What kind it is
6644 (ubyte *) &val, // value to set
6645 &dwLen // How many bytes to set
6648 if (lResult == ERROR_SUCCESS) {
6656 if (dx_version < 3) {
6657 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6658 "latest version of DirectX at:\n\n"
6659 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6661 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6662 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6667 //=====================================================
6668 // Make sure we're running in the right directory.
6671 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6672 char *p = exe_dir + strlen(exe_dir);
6674 // chop off the filename
6675 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6681 if ( strlen(exe_dir) > 0 ) {
6682 SetCurrentDirectory(exe_dir);
6685 // check for updated freespace.exe
6686 game_maybe_update_launcher(exe_dir);
6692 extern void windebug_memwatch_init();
6693 windebug_memwatch_init();
6697 parse_cmdline(szCmdLine);
6699 #ifdef STANDALONE_ONLY_BUILD
6701 nprintf(("Network", "Standalone running"));
6704 nprintf(("Network", "Standalone running"));
6712 // maybe spew pof stuff
6713 if(Cmdline_spew_pof_info){
6714 game_spew_pof_info();
6719 // non-demo, non-standalone, play the intro movie
6724 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) ){
6726 #if defined(OEM_BUILD)
6727 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6729 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6730 #endif // defined(OEM_BUILD)
6735 if ( !Is_standalone ) {
6737 // release -- movies always play
6740 // 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
6742 // movie_play( NOX("intro.mve"), 0 );
6744 // debug version, movie will only play with -showmovies
6745 #else if !defined(NDEBUG)
6748 // movie_play( NOX("intro.mve"), 0);
6751 if ( Cmdline_show_movies )
6752 movie_play( NOX("intro.mve"), 0 );
6761 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6763 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6767 // only important for non THREADED mode
6770 state = gameseq_process_events();
6771 if ( state == GS_STATE_QUIT_GAME ){
6778 demo_upsell_show_screens();
6780 #elif defined(OEM_BUILD)
6781 // show upsell screens on exit
6782 oem_upsell_show_screens();
6789 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6795 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6797 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6799 // Do nothing here - RecordExceptionInfo() has already done
6800 // everything that is needed. Actually this code won't even
6801 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6802 // the __except clause.
6807 // launcher the fslauncher program on exit
6808 void game_launch_launcher_on_exit()
6811 PROCESS_INFORMATION pi;
6812 char cmd_line[2048];
6813 char original_path[1024] = "";
6815 memset( &si, 0, sizeof(STARTUPINFO) );
6819 _getcwd(original_path, 1023);
6821 // set up command line
6822 strcpy(cmd_line, original_path);
6823 strcat(cmd_line, "\\");
6824 strcat(cmd_line, LAUNCHER_FNAME);
6825 strcat(cmd_line, " -straight_to_update");
6827 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6828 cmd_line, // pointer to command line string
6829 NULL, // pointer to process security attributes
6830 NULL, // pointer to thread security attributes
6831 FALSE, // handle inheritance flag
6832 CREATE_DEFAULT_ERROR_MODE, // creation flags
6833 NULL, // pointer to new environment block
6834 NULL, // pointer to current directory name
6835 &si, // pointer to STARTUPINFO
6836 &pi // pointer to PROCESS_INFORMATION
6838 // to eliminate build warnings
6845 // This function is called when FreeSpace terminates normally.
6847 void game_shutdown(void)
6851 // don't ever flip a page on the standalone!
6852 if(!(Game_mode & GM_STANDALONE_SERVER)){
6858 // if the player has left the "player select" screen and quit the game without actually choosing
6859 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6860 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6864 // load up common multiplayer icons
6865 multi_unload_common_icons();
6867 shockwave_close(); // release any memory used by shockwave system
6868 fireball_close(); // free fireball system
6869 ship_close(); // free any memory that was allocated for the ships
6870 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6871 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6872 bm_unload_all(); // free bitmaps
6873 mission_campaign_close(); // close out the campaign stuff
6874 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6876 #ifdef MULTI_USE_LAG
6880 // the menu close functions will unload the bitmaps if they were displayed during the game
6881 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6884 training_menu_close();
6887 extern void joy_close();
6890 audiostream_close();
6892 event_music_close();
6896 // HACKITY HACK HACK
6897 // if this flag is set, we should be firing up the launcher when exiting freespace
6898 extern int Multi_update_fireup_launcher_on_exit;
6899 if(Multi_update_fireup_launcher_on_exit){
6900 game_launch_launcher_on_exit();
6904 // game_stop_looped_sounds()
6906 // This function will call the appropriate stop looped sound functions for those
6907 // modules which use looping sounds. It is not enough just to stop a looping sound
6908 // at the DirectSound level, the game is keeping track of looping sounds, and this
6909 // function is used to inform the game that looping sounds are being halted.
6911 void game_stop_looped_sounds()
6913 hud_stop_looped_locking_sounds();
6914 hud_stop_looped_engine_sounds();
6915 afterburner_stop_sounds();
6916 player_stop_looped_sounds();
6917 obj_snd_stop_all(); // stop all object-linked persistant sounds
6918 game_stop_subspace_ambient_sound();
6919 snd_stop(Radar_static_looping);
6920 Radar_static_looping = -1;
6921 snd_stop(Target_static_looping);
6922 shipfx_stop_engine_wash_sound();
6923 Target_static_looping = -1;
6926 //////////////////////////////////////////////////////////////////////////
6928 // Code for supporting an animating mouse pointer
6931 //////////////////////////////////////////////////////////////////////////
6933 typedef struct animating_obj
6942 static animating_obj Animating_mouse;
6944 // ----------------------------------------------------------------------------
6945 // init_animating_pointer()
6947 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6948 // gets properly initialized
6950 void init_animating_pointer()
6952 Animating_mouse.first_frame = -1;
6953 Animating_mouse.num_frames = 0;
6954 Animating_mouse.current_frame = -1;
6955 Animating_mouse.time = 0.0f;
6956 Animating_mouse.elapsed_time = 0.0f;
6959 // ----------------------------------------------------------------------------
6960 // load_animating_pointer()
6962 // Called at game init to load in the frames for the animating mouse pointer
6964 // input: filename => filename of animation file that holds the animation
6966 void load_animating_pointer(char *filename, int dx, int dy)
6971 init_animating_pointer();
6973 am = &Animating_mouse;
6974 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
6975 if ( am->first_frame == -1 )
6976 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
6977 am->current_frame = 0;
6978 am->time = am->num_frames / i2fl(fps);
6981 // ----------------------------------------------------------------------------
6982 // unload_animating_pointer()
6984 // Called at game shutdown to free the memory used to store the animation frames
6986 void unload_animating_pointer()
6991 am = &Animating_mouse;
6992 for ( i = 0; i < am->num_frames; i++ ) {
6993 Assert( (am->first_frame+i) >= 0 );
6994 bm_release(am->first_frame + i);
6997 am->first_frame = -1;
6999 am->current_frame = -1;
7002 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7003 void game_render_mouse(float frametime)
7008 // if animating cursor exists, play the next frame
7009 am = &Animating_mouse;
7010 if ( am->first_frame != -1 ) {
7011 mouse_get_pos(&mx, &my);
7012 am->elapsed_time += frametime;
7013 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7014 if ( am->current_frame >= am->num_frames ) {
7015 am->current_frame = 0;
7016 am->elapsed_time = 0.0f;
7018 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7022 // ----------------------------------------------------------------------------
7023 // game_maybe_draw_mouse()
7025 // determines whether to draw the mouse pointer at all, and what frame of
7026 // animation to use if the mouse is animating
7028 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7030 // input: frametime => elapsed frame time in seconds since last call
7032 void game_maybe_draw_mouse(float frametime)
7036 game_state = gameseq_get_state();
7038 switch ( game_state ) {
7039 case GS_STATE_GAME_PAUSED:
7040 // case GS_STATE_MULTI_PAUSED:
7041 case GS_STATE_GAME_PLAY:
7042 case GS_STATE_DEATH_DIED:
7043 case GS_STATE_DEATH_BLEW_UP:
7044 if ( popup_active() || popupdead_is_active() ) {
7056 if ( !Mouse_hidden )
7057 game_render_mouse(frametime);
7061 void game_do_training_checks()
7065 waypoint_list *wplp;
7067 if (Training_context & TRAINING_CONTEXT_SPEED) {
7068 s = (int) Player_obj->phys_info.fspeed;
7069 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7070 if (!Training_context_speed_set) {
7071 Training_context_speed_set = 1;
7072 Training_context_speed_timestamp = timestamp();
7076 Training_context_speed_set = 0;
7079 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7080 wplp = &Waypoint_lists[Training_context_path];
7081 if (wplp->count > Training_context_goal_waypoint) {
7082 i = Training_context_goal_waypoint;
7084 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7085 if (d <= Training_context_distance) {
7086 Training_context_at_waypoint = i;
7087 if (Training_context_goal_waypoint == i) {
7088 Training_context_goal_waypoint++;
7089 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7096 if (i == wplp->count)
7099 } while (i != Training_context_goal_waypoint);
7103 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7104 Players_target = Player_ai->target_objnum;
7105 Players_targeted_subsys = Player_ai->targeted_subsys;
7106 Players_target_timestamp = timestamp();
7110 /////////// Following is for event debug view screen
7114 #define EVENT_DEBUG_MAX 5000
7115 #define EVENT_DEBUG_EVENT 0x8000
7117 int Event_debug_index[EVENT_DEBUG_MAX];
7120 void game_add_event_debug_index(int n, int indent)
7122 if (ED_count < EVENT_DEBUG_MAX)
7123 Event_debug_index[ED_count++] = n | (indent << 16);
7126 void game_add_event_debug_sexp(int n, int indent)
7131 if (Sexp_nodes[n].first >= 0) {
7132 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7133 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7137 game_add_event_debug_index(n, indent);
7138 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7139 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7141 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7144 void game_event_debug_init()
7149 for (e=0; e<Num_mission_events; e++) {
7150 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7151 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7155 void game_show_event_debug(float frametime)
7159 int font_height, font_width;
7161 static int scroll_offset = 0;
7163 k = game_check_key();
7169 if (scroll_offset < 0)
7179 scroll_offset -= 20;
7180 if (scroll_offset < 0)
7185 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7189 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7195 gr_set_color_fast(&Color_bright);
7197 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7199 gr_set_color_fast(&Color_normal);
7201 gr_get_string_size(&font_width, &font_height, NOX("test"));
7202 y_max = gr_screen.max_h - font_height - 5;
7206 while (k < ED_count) {
7207 if (y_index > y_max)
7210 z = Event_debug_index[k];
7211 if (z & EVENT_DEBUG_EVENT) {
7213 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7214 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7215 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7216 Mission_events[z].repeat_count, Mission_events[z].interval);
7224 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7225 switch (Sexp_nodes[z & 0x7fff].value) {
7227 strcat(buf, NOX(" (True)"));
7231 strcat(buf, NOX(" (False)"));
7234 case SEXP_KNOWN_TRUE:
7235 strcat(buf, NOX(" (Always true)"));
7238 case SEXP_KNOWN_FALSE:
7239 strcat(buf, NOX(" (Always false)"));
7242 case SEXP_CANT_EVAL:
7243 strcat(buf, NOX(" (Can't eval)"));
7247 case SEXP_NAN_FOREVER:
7248 strcat(buf, NOX(" (Not a number)"));
7253 gr_printf(10, y_index, buf);
7254 y_index += font_height;
7267 extern int Tmap_npixels;
7269 int Tmap_num_too_big = 0;
7270 int Num_models_needing_splitting = 0;
7272 void Time_model( int modelnum )
7274 // mprintf(( "Timing ship '%s'\n", si->name ));
7276 vector eye_pos, model_pos;
7277 matrix eye_orient, model_orient;
7279 polymodel *pm = model_get( modelnum );
7281 int l = strlen(pm->filename);
7283 if ( (l == '/') || (l=='\\') || (l==':')) {
7289 char *pof_file = &pm->filename[l];
7291 int model_needs_splitting = 0;
7293 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7295 for (i=0; i<pm->n_textures; i++ ) {
7296 char filename[1024];
7299 int bmp_num = pm->original_textures[i];
7300 if ( bmp_num > -1 ) {
7301 bm_get_palette(pm->original_textures[i], pal, filename );
7303 bm_get_info( pm->original_textures[i],&w, &h );
7306 if ( (w > 512) || (h > 512) ) {
7307 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7309 model_needs_splitting++;
7312 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7316 if ( model_needs_splitting ) {
7317 Num_models_needing_splitting++;
7319 eye_orient = model_orient = vmd_identity_matrix;
7320 eye_pos = model_pos = vmd_zero_vector;
7322 eye_pos.z = -pm->rad*2.0f;
7324 vector eye_to_model;
7326 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7327 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7329 fix t1 = timer_get_fixed_seconds();
7332 ta.p = ta.b = ta.h = 0.0f;
7337 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7339 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7341 modelstats_num_polys = modelstats_num_verts = 0;
7343 while( ta.h < PI2 ) {
7346 vm_angles_2_matrix(&m1, &ta );
7347 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7354 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7356 model_clear_instance( modelnum );
7357 model_set_detail_level(0); // use highest detail level
7358 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7366 int k = key_inkey();
7367 if ( k == KEY_ESC ) {
7372 fix t2 = timer_get_fixed_seconds();
7374 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7375 //bitmaps_used_this_frame /= framecount;
7377 modelstats_num_polys /= framecount;
7378 modelstats_num_verts /= framecount;
7380 Tmap_npixels /=framecount;
7383 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7384 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 );
7385 // 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 );
7391 int Time_models = 0;
7392 DCF_BOOL( time_models, Time_models );
7394 void Do_model_timings_test()
7398 if ( !Time_models ) return;
7400 mprintf(( "Timing models!\n" ));
7404 ubyte model_used[MAX_POLYGON_MODELS];
7405 int model_id[MAX_POLYGON_MODELS];
7406 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7411 for (i=0; i<Num_ship_types; i++ ) {
7412 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7414 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7415 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7418 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7419 if ( !Texture_fp ) return;
7421 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7422 if ( !Time_fp ) return;
7424 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7425 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7427 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7428 if ( model_used[i] ) {
7429 Time_model( model_id[i] );
7433 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7434 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7443 // Call this function when you want to inform the player that a feature is not
7444 // enabled in the DEMO version of FreSpace
7445 void game_feature_not_in_demo_popup()
7447 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7450 // format the specified time (fixed point) into a nice string
7451 void game_format_time(fix m_time,char *time_str)
7454 int hours,minutes,seconds;
7457 mtime = f2fl(m_time);
7459 // get the hours, minutes and seconds
7460 hours = (int)(mtime / 3600.0f);
7462 mtime -= (3600.0f * (float)hours);
7464 seconds = (int)mtime%60;
7465 minutes = (int)mtime/60;
7467 // print the hour if necessary
7469 sprintf(time_str,XSTR( "%d:", 201),hours);
7470 // if there are less than 10 minutes, print a leading 0
7472 strcpy(tmp,NOX("0"));
7473 strcat(time_str,tmp);
7477 // print the minutes
7479 sprintf(tmp,XSTR( "%d:", 201),minutes);
7480 strcat(time_str,tmp);
7482 sprintf(time_str,XSTR( "%d:", 201),minutes);
7485 // print the seconds
7487 strcpy(tmp,NOX("0"));
7488 strcat(time_str,tmp);
7490 sprintf(tmp,"%d",seconds);
7491 strcat(time_str,tmp);
7494 // Stuff version string in *str.
7495 void get_version_string(char *str)
7498 if ( FS_VERSION_BUILD == 0 ) {
7499 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7501 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7504 #if defined (FS2_DEMO)
7506 #elif defined (OEM_BUILD)
7507 strcat(str, " (OEM)");
7513 char myname[_MAX_PATH];
7514 int namelen, major, minor, build, waste;
7515 unsigned int buf_size;
7521 // Find my EXE file name
7522 hMod = GetModuleHandle(NULL);
7523 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7525 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7526 infop = (char *)malloc(version_size);
7527 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7529 // get the product version
7530 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7531 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7533 sprintf(str,"Dv%d.%02d",major, minor);
7535 sprintf(str,"v%d.%02d",major, minor);
7540 void get_version_string_short(char *str)
7542 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7545 // ----------------------------------------------------------------
7547 // OEM UPSELL SCREENS BEGIN
7549 // ----------------------------------------------------------------
7550 #if defined(OEM_BUILD)
7552 #define NUM_OEM_UPSELL_SCREENS 3
7553 #define OEM_UPSELL_SCREEN_DELAY 10000
7555 static int Oem_upsell_bitmaps_loaded = 0;
7556 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7557 static int Oem_upsell_screen_number = 0;
7558 static int Oem_upsell_show_next_bitmap_time;
7561 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7574 static int Oem_normal_cursor = -1;
7575 static int Oem_web_cursor = -1;
7576 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7577 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7579 void oem_upsell_next_screen()
7581 Oem_upsell_screen_number++;
7582 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7583 // extra long delay, mouse shown on last upsell
7584 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7588 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7592 void oem_upsell_load_bitmaps()
7596 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7597 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7601 void oem_upsell_unload_bitmaps()
7605 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7606 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7607 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7612 Oem_upsell_bitmaps_loaded = 0;
7615 // clickable hotspot on 3rd OEM upsell screen
7616 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7618 28, 350, 287, 96 // x, y, w, h
7621 45, 561, 460, 152 // x, y, w, h
7625 void oem_upsell_show_screens()
7627 int current_time, k;
7630 if ( !Oem_upsell_bitmaps_loaded ) {
7631 oem_upsell_load_bitmaps();
7632 Oem_upsell_bitmaps_loaded = 1;
7635 // may use upsell screens more than once
7636 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7637 Oem_upsell_screen_number = 0;
7643 int nframes; // used to pass, not really needed (should be 1)
7644 Oem_normal_cursor = gr_get_cursor_bitmap();
7645 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7646 Assert(Oem_web_cursor >= 0);
7647 if (Oem_web_cursor < 0) {
7648 Oem_web_cursor = Oem_normal_cursor;
7653 //oem_reset_trailer_timer();
7655 current_time = timer_get_milliseconds();
7660 // advance screen on keypress or timeout
7661 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7662 oem_upsell_next_screen();
7665 // check if we are done
7666 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7667 Oem_upsell_screen_number--;
7670 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7675 // show me the upsell
7676 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7677 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7681 // if this is the 3rd upsell, make it clickable, d00d
7682 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7684 int button_state = mouse_get_pos(&mx, &my);
7685 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])
7686 && (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]) )
7689 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7692 if (button_state & MOUSE_LEFT_BUTTON) {
7694 multi_pxo_url(OEM_UPSELL_URL);
7698 // switch cursor back to normal one
7699 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7704 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7714 oem_upsell_unload_bitmaps();
7716 // switch cursor back to normal one
7717 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7721 #endif // defined(OEM_BUILD)
7722 // ----------------------------------------------------------------
7724 // OEM UPSELL SCREENS END
7726 // ----------------------------------------------------------------
7730 // ----------------------------------------------------------------
7732 // DEMO UPSELL SCREENS BEGIN
7734 // ----------------------------------------------------------------
7738 //#define NUM_DEMO_UPSELL_SCREENS 4
7740 #define NUM_DEMO_UPSELL_SCREENS 2
7741 #define DEMO_UPSELL_SCREEN_DELAY 3000
7743 static int Demo_upsell_bitmaps_loaded = 0;
7744 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7745 static int Demo_upsell_screen_number = 0;
7746 static int Demo_upsell_show_next_bitmap_time;
7749 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7762 void demo_upsell_next_screen()
7764 Demo_upsell_screen_number++;
7765 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7766 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7768 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7772 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7773 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7774 #ifndef HARDWARE_ONLY
7775 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7782 void demo_upsell_load_bitmaps()
7786 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7787 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7791 void demo_upsell_unload_bitmaps()
7795 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7796 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7797 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7802 Demo_upsell_bitmaps_loaded = 0;
7805 void demo_upsell_show_screens()
7807 int current_time, k;
7810 if ( !Demo_upsell_bitmaps_loaded ) {
7811 demo_upsell_load_bitmaps();
7812 Demo_upsell_bitmaps_loaded = 1;
7815 // may use upsell screens more than once
7816 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7817 Demo_upsell_screen_number = 0;
7824 demo_reset_trailer_timer();
7826 current_time = timer_get_milliseconds();
7833 // don't time out, wait for keypress
7835 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7836 demo_upsell_next_screen();
7841 demo_upsell_next_screen();
7844 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7845 Demo_upsell_screen_number--;
7848 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7853 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7854 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7859 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7869 demo_upsell_unload_bitmaps();
7874 // ----------------------------------------------------------------
7876 // DEMO UPSELL SCREENS END
7878 // ----------------------------------------------------------------
7881 // ----------------------------------------------------------------
7883 // Subspace Ambient Sound START
7885 // ----------------------------------------------------------------
7887 static int Subspace_ambient_left_channel = -1;
7888 static int Subspace_ambient_right_channel = -1;
7891 void game_start_subspace_ambient_sound()
7893 if ( Subspace_ambient_left_channel < 0 ) {
7894 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7897 if ( Subspace_ambient_right_channel < 0 ) {
7898 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7902 void game_stop_subspace_ambient_sound()
7904 if ( Subspace_ambient_left_channel >= 0 ) {
7905 snd_stop(Subspace_ambient_left_channel);
7906 Subspace_ambient_left_channel = -1;
7909 if ( Subspace_ambient_right_channel >= 0 ) {
7910 snd_stop(Subspace_ambient_right_channel);
7911 Subspace_ambient_right_channel = -1;
7915 // ----------------------------------------------------------------
7917 // Subspace Ambient Sound END
7919 // ----------------------------------------------------------------
7921 // ----------------------------------------------------------------
7923 // CDROM detection code START
7925 // ----------------------------------------------------------------
7927 #define CD_SIZE_72_MINUTE_MAX (697000000)
7929 uint game_get_cd_used_space(char *path)
7932 char use_path[512] = "";
7933 char sub_path[512] = "";
7934 WIN32_FIND_DATA find;
7937 // recurse through all files and directories
7938 strcpy(use_path, path);
7939 strcat(use_path, "*.*");
7940 find_handle = FindFirstFile(use_path, &find);
7943 if(find_handle == INVALID_HANDLE_VALUE){
7949 // subdirectory. make sure to ignore . and ..
7950 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
7952 strcpy(sub_path, path);
7953 strcat(sub_path, find.cFileName);
7954 strcat(sub_path, "\\");
7955 total += game_get_cd_used_space(sub_path);
7957 total += (uint)find.nFileSizeLow;
7959 } while(FindNextFile(find_handle, &find));
7962 FindClose(find_handle);
7969 // if volume_name is non-null, the CD name must match that
7970 int find_freespace_cd(char *volume_name)
7972 char oldpath[MAX_PATH];
7976 int volume_match = 0;
7980 GetCurrentDirectory(MAX_PATH, oldpath);
7982 for (i = 0; i < 26; i++)
7988 path[0] = (char)('A'+i);
7989 if (GetDriveType(path) == DRIVE_CDROM) {
7991 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
7992 nprintf(("CD", "CD volume: %s\n", volume));
7994 // check for any CD volume
7995 int volume1_present = 0;
7996 int volume2_present = 0;
7997 int volume3_present = 0;
7999 char full_check[512] = "";
8001 // look for setup.exe
8002 strcpy(full_check, path);
8003 strcat(full_check, "setup.exe");
8004 find_handle = _findfirst(full_check, &find);
8005 if(find_handle != -1){
8006 volume1_present = 1;
8007 _findclose(find_handle);
8010 // look for intro.mve
8011 strcpy(full_check, path);
8012 strcat(full_check, "intro.mve");
8013 find_handle = _findfirst(full_check, &find);
8014 if(find_handle != -1){
8015 volume2_present = 1;
8016 _findclose(find_handle);
8019 // look for endpart1.mve
8020 strcpy(full_check, path);
8021 strcat(full_check, "endpart1.mve");
8022 find_handle = _findfirst(full_check, &find);
8023 if(find_handle != -1){
8024 volume3_present = 1;
8025 _findclose(find_handle);
8028 // see if we have the specific CD we're looking for
8029 if ( volume_name ) {
8031 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8035 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8039 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8043 if ( volume1_present || volume2_present || volume3_present ) {
8048 // 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
8049 if ( volume_match ){
8051 // 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
8052 if(volume2_present || volume3_present) {
8053 // first step - check to make sure its a cdrom
8054 if(GetDriveType(path) != DRIVE_CDROM){
8058 #if !defined(OEM_BUILD)
8059 // oem not on 80 min cds, so dont check tha size
8061 uint used_space = game_get_cd_used_space(path);
8062 if(used_space < CD_SIZE_72_MINUTE_MAX){
8065 #endif // !defined(OEM_BUILD)
8073 #endif // RELEASE_REAL
8079 SetCurrentDirectory(oldpath);
8083 int set_cdrom_path(int drive_num)
8087 if (drive_num < 0) { //no CD
8089 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8092 strcpy(Game_CDROM_dir,""); //set directory
8096 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8112 i = find_freespace_cd();
8114 rval = set_cdrom_path(i);
8118 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8120 nprintf(("CD", "FreeSpace CD not found\n"));
8128 int Last_cd_label_found = 0;
8129 char Last_cd_label[256];
8131 int game_cd_changed()
8137 if ( strlen(Game_CDROM_dir) == 0 ) {
8141 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8143 if ( found != Last_cd_label_found ) {
8144 Last_cd_label_found = found;
8146 mprintf(( "CD '%s' was inserted\n", label ));
8149 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8153 if ( Last_cd_label_found ) {
8154 if ( !stricmp( Last_cd_label, label )) {
8155 //mprintf(( "CD didn't change\n" ));
8157 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8161 // none found before, none found now.
8162 //mprintf(( "still no CD...\n" ));
8166 Last_cd_label_found = found;
8168 strcpy( Last_cd_label, label );
8170 strcpy( Last_cd_label, "" );
8176 // check if _any_ FreeSpace2 CDs are in the drive
8177 // return: 1 => CD now in drive
8178 // 0 => Could not find CD, they refuse to put it in the drive
8179 int game_do_cd_check(char *volume_name)
8181 #if !defined(GAME_CD_CHECK)
8187 int num_attempts = 0;
8188 int refresh_files = 0;
8190 int path_set_ok, popup_rval;
8192 cd_drive_num = find_freespace_cd(volume_name);
8193 path_set_ok = set_cdrom_path(cd_drive_num);
8194 if ( path_set_ok ) {
8196 if ( refresh_files ) {
8208 // no CD found, so prompt user
8209 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8211 if ( popup_rval != 1 ) {
8216 if ( num_attempts++ > 5 ) {
8227 // check if _any_ FreeSpace2 CDs are in the drive
8228 // return: 1 => CD now in drive
8229 // 0 => Could not find CD, they refuse to put it in the drive
8230 int game_do_cd_check_specific(char *volume_name, int cdnum)
8235 int num_attempts = 0;
8236 int refresh_files = 0;
8238 int path_set_ok, popup_rval;
8240 cd_drive_num = find_freespace_cd(volume_name);
8241 path_set_ok = set_cdrom_path(cd_drive_num);
8242 if ( path_set_ok ) {
8244 if ( refresh_files ) {
8255 // no CD found, so prompt user
8256 #if defined(DVD_MESSAGE_HACK)
8257 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8259 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8262 if ( popup_rval != 1 ) {
8267 if ( num_attempts++ > 5 ) {
8277 // only need to do this in RELEASE_REAL
8278 int game_do_cd_mission_check(char *filename)
8284 fs_builtin_mission *m = game_find_builtin_mission(filename);
8286 // check for changed CD
8287 if(game_cd_changed()){
8292 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8296 // not builtin, so do a general check (any FS2 CD will do)
8298 return game_do_cd_check();
8301 // does not have any CD requirement, do a general check
8302 if(strlen(m->cd_volume) <= 0){
8303 return game_do_cd_check();
8307 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8309 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8311 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8314 return game_do_cd_check();
8317 // did we find the cd?
8318 if(find_freespace_cd(m->cd_volume) >= 0){
8322 // make sure the volume exists
8323 int num_attempts = 0;
8324 int refresh_files = 0;
8326 int path_set_ok, popup_rval;
8328 cd_drive_num = find_freespace_cd(m->cd_volume);
8329 path_set_ok = set_cdrom_path(cd_drive_num);
8330 if ( path_set_ok ) {
8332 if ( refresh_files ) {
8339 // no CD found, so prompt user
8340 #if defined(DVD_MESSAGE_HACK)
8341 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8343 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8347 if ( popup_rval != 1 ) {
8352 if ( num_attempts++ > 5 ) {
8364 // ----------------------------------------------------------------
8366 // CDROM detection code END
8368 // ----------------------------------------------------------------
8370 // ----------------------------------------------------------------
8371 // SHIPS TBL VERIFICATION STUFF
8374 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8375 #define NUM_SHIPS_TBL_CHECKSUMS 1
8377 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8378 -463907578, // US - beta 1
8379 1696074201, // FS2 demo
8382 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8383 // -1022810006, // 1.0 FULL
8384 -1254285366 // 1.2 FULL (German)
8387 void verify_ships_tbl()
8391 Game_ships_tbl_valid = 1;
8397 // detect if the packfile exists
8398 CFILE *detect = cfopen("ships.tbl", "rb");
8399 Game_ships_tbl_valid = 0;
8403 Game_ships_tbl_valid = 0;
8407 // get the long checksum of the file
8409 cfseek(detect, 0, SEEK_SET);
8410 cf_chksum_long(detect, &file_checksum);
8414 // now compare the checksum/filesize against known #'s
8415 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8416 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8417 Game_ships_tbl_valid = 1;
8424 DCF(shipspew, "display the checksum for the current ships.tbl")
8427 CFILE *detect = cfopen("ships.tbl", "rb");
8428 // get the long checksum of the file
8430 cfseek(detect, 0, SEEK_SET);
8431 cf_chksum_long(detect, &file_checksum);
8434 dc_printf("%d", file_checksum);
8437 // ----------------------------------------------------------------
8438 // WEAPONS TBL VERIFICATION STUFF
8441 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8442 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8444 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8445 141718090, // US - beta 1
8446 -266420030, // demo 1
8449 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8450 // 399297860, // 1.0 FULL
8451 -553984927 // 1.2 FULL (german)
8454 void verify_weapons_tbl()
8458 Game_weapons_tbl_valid = 1;
8464 // detect if the packfile exists
8465 CFILE *detect = cfopen("weapons.tbl", "rb");
8466 Game_weapons_tbl_valid = 0;
8470 Game_weapons_tbl_valid = 0;
8474 // get the long checksum of the file
8476 cfseek(detect, 0, SEEK_SET);
8477 cf_chksum_long(detect, &file_checksum);
8481 // now compare the checksum/filesize against known #'s
8482 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8483 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8484 Game_weapons_tbl_valid = 1;
8491 DCF(wepspew, "display the checksum for the current weapons.tbl")
8494 CFILE *detect = cfopen("weapons.tbl", "rb");
8495 // get the long checksum of the file
8497 cfseek(detect, 0, SEEK_SET);
8498 cf_chksum_long(detect, &file_checksum);
8501 dc_printf("%d", file_checksum);
8504 // if the game is running using hacked data
8505 int game_hacked_data()
8508 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8516 void display_title_screen()
8518 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8519 ///int title_bitmap;
8522 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8523 if (title_bitmap == -1) {
8528 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8529 extern void d3d_start_frame();
8534 gr_set_bitmap(title_bitmap);
8540 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8541 extern void d3d_stop_frame();
8548 bm_unload(title_bitmap);
8549 #endif // FS2_DEMO || OEM_BUILD
8552 // return true if the game is running with "low memory", which is less than 48MB
8553 bool game_using_low_mem()
8555 if (Use_low_mem == 0) {