2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.4 2002/05/27 22:46:52 theoddone33
11 * Remove more undefined symbols
13 * Revision 1.3 2002/05/26 23:31:18 relnev
14 * added a few files that needed to be compiled
16 * freespace.cpp: now compiles
18 * Revision 1.2 2002/05/07 03:16:44 theoddone33
19 * The Great Newline Fix
21 * Revision 1.1.1.1 2002/05/03 03:28:09 root
25 * 201 6/16/00 3:15p Jefff
26 * sim of the year dvd version changes, a few german soty localization
29 * 200 11/03/99 11:06a Jefff
32 * 199 10/26/99 5:07p Jamest
33 * fixed jeffs dumb debug code
35 * 198 10/25/99 5:53p Jefff
36 * call control_config_common_init() on startup
38 * 197 10/14/99 10:18a Daveb
39 * Fixed incorrect CD checking problem on standalone server.
41 * 196 10/13/99 9:22a Daveb
42 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
43 * related to movies. Fixed launcher spawning from PXO screen.
45 * 195 10/06/99 11:05a Jefff
46 * new oem upsell 3 hotspot coords
48 * 194 10/06/99 10:31a Jefff
51 * 193 10/01/99 9:10a Daveb
54 * 192 9/15/99 4:57a Dave
55 * Updated ships.tbl checksum
57 * 191 9/15/99 3:58a Dave
58 * Removed framerate warning at all times.
60 * 190 9/15/99 3:16a Dave
61 * Remove mt-011.fs2 from the builtin mission list.
63 * 189 9/15/99 1:45a Dave
64 * Don't init joystick on standalone. Fixed campaign mode on standalone.
65 * Fixed no-score-report problem in TvT
67 * 188 9/14/99 6:08a Dave
68 * Updated (final) single, multi, and campaign list.
70 * 187 9/14/99 3:26a Dave
71 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
72 * respawn-too-early problem. Made a few crash points safe.
74 * 186 9/13/99 4:52p Dave
77 * 185 9/12/99 8:09p Dave
78 * Fixed problem where skip-training button would cause mission messages
79 * not to get paged out for the current mission.
81 * 184 9/10/99 11:53a Dave
82 * Shutdown graphics before sound to eliminate apparent lockups when
83 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
85 * 183 9/09/99 11:40p Dave
86 * Handle an Assert() in beam code. Added supernova sounds. Play the right
87 * 2 end movies properly, based upon what the player did in the mission.
89 * 182 9/08/99 10:29p Dave
90 * Make beam sound pausing and unpausing much safer.
92 * 181 9/08/99 10:01p Dave
93 * Make sure game won't run in a drive's root directory. Make sure
94 * standalone routes suqad war messages properly to the host.
96 * 180 9/08/99 3:22p Dave
97 * Updated builtin mission list.
99 * 179 9/08/99 12:01p Jefff
100 * fixed Game_builtin_mission_list typo on Training-2.fs2
102 * 178 9/08/99 9:48a Andsager
103 * Add force feedback for engine wash.
105 * 177 9/07/99 4:01p Dave
106 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
107 * does everything properly (setting up address when binding). Remove
108 * black rectangle background from UI_INPUTBOX.
110 * 176 9/13/99 2:40a Dave
111 * Comment in full 80 minute CD check for RELEASE_REAL builds.
113 * 175 9/06/99 6:38p Dave
114 * Improved CD detection code.
116 * 174 9/06/99 1:30a Dave
117 * Intermediate checkin. Started on enforcing CD-in-drive to play the
120 * 173 9/06/99 1:16a Dave
121 * Make sure the user sees the intro movie.
123 * 172 9/04/99 8:00p Dave
124 * Fixed up 1024 and 32 bit movie support.
126 * 171 9/03/99 1:32a Dave
127 * CD checking by act. Added support to play 2 cutscenes in a row
128 * seamlessly. Fixed super low level cfile bug related to files in the
129 * root directory of a CD. Added cheat code to set campaign mission # in
132 * 170 9/01/99 10:49p Dave
133 * Added nice SquadWar checkbox to the client join wait screen.
135 * 169 9/01/99 10:14a Dave
138 * 168 8/29/99 4:51p Dave
139 * Fixed damaged checkin.
141 * 167 8/29/99 4:18p Andsager
142 * New "burst" limit for friendly damage. Also credit more damage done
143 * against large friendly ships.
145 * 166 8/27/99 6:38p Alanl
146 * crush the blasted repeating messages bug
148 * 164 8/26/99 9:09p Dave
149 * Force framerate check in everything but a RELEASE_REAL build.
151 * 163 8/26/99 9:45a Dave
152 * First pass at easter eggs and cheats.
154 * 162 8/24/99 8:55p Dave
155 * Make sure nondimming pixels work properly in tech menu.
157 * 161 8/24/99 1:49a Dave
158 * Fixed client-side afterburner stuttering. Added checkbox for no version
159 * checking on PXO join. Made button info passing more friendly between
162 * 160 8/22/99 5:53p Dave
163 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
164 * instead of ship designations for multiplayer players.
166 * 159 8/22/99 1:19p Dave
167 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
168 * which d3d cards are detected.
170 * 158 8/20/99 2:09p Dave
171 * PXO banner cycling.
173 * 157 8/19/99 10:59a Dave
174 * Packet loss detection.
176 * 156 8/19/99 10:12a Alanl
177 * preload mission-specific messages on machines greater than 48MB
179 * 155 8/16/99 4:04p Dave
180 * Big honking checkin.
182 * 154 8/11/99 5:54p Dave
183 * Fixed collision problem. Fixed standalone ghost problem.
185 * 153 8/10/99 7:59p Jefff
188 * 152 8/10/99 6:54p Dave
189 * Mad optimizations. Added paging to the nebula effect.
191 * 151 8/10/99 3:44p Jefff
192 * loads Intelligence information on startup
194 * 150 8/09/99 3:47p Dave
195 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
196 * non-nebula missions.
198 * 149 8/09/99 2:21p Andsager
199 * Fix patching from multiplayer direct to launcher update tab.
201 * 148 8/09/99 10:36a Dave
202 * Version info for game.
204 * 147 8/06/99 9:46p Dave
205 * Hopefully final changes for the demo.
207 * 146 8/06/99 3:34p Andsager
208 * Make title version info "(D)" -> "D" show up nicely
210 * 145 8/06/99 2:59p Adamp
211 * Fixed NT launcher/update problem.
213 * 144 8/06/99 1:52p Dave
214 * Bumped up MAX_BITMAPS for the demo.
216 * 143 8/06/99 12:17p Andsager
217 * Demo: down to just 1 demo dog
219 * 142 8/05/99 9:39p Dave
220 * Yet another new checksum.
222 * 141 8/05/99 6:19p Dave
223 * New demo checksums.
225 * 140 8/05/99 5:31p Andsager
226 * Up demo version 1.01
228 * 139 8/05/99 4:22p Andsager
229 * No time limit on upsell screens. Reverse order of display of upsell
232 * 138 8/05/99 4:17p Dave
233 * Tweaks to client interpolation.
235 * 137 8/05/99 3:52p Danw
237 * 136 8/05/99 3:01p Danw
239 * 135 8/05/99 2:43a Anoop
240 * removed duplicate definition.
242 * 134 8/05/99 2:13a Dave
245 * 133 8/05/99 2:05a Dave
248 * 132 8/05/99 1:22a Andsager
251 * 131 8/04/99 9:51p Andsager
252 * Add title screen to demo
254 * 130 8/04/99 6:47p Jefff
255 * fixed link error resulting from #ifdefs
257 * 129 8/04/99 6:26p Dave
258 * Updated ship tbl checksum.
260 * 128 8/04/99 5:40p Andsager
261 * Add multiple demo dogs
263 * 127 8/04/99 5:36p Andsager
264 * Show upsell screens at end of demo campaign before returning to main
267 * 126 8/04/99 11:42a Danw
268 * tone down EAX reverb
270 * 125 8/04/99 11:23a Dave
271 * Updated demo checksums.
273 * 124 8/03/99 11:02p Dave
274 * Maybe fixed sync problems in multiplayer.
276 * 123 8/03/99 6:21p Jefff
279 * 122 8/03/99 3:44p Andsager
280 * Launch laucher if trying to run FS without first having configured
283 * 121 8/03/99 12:45p Dave
286 * 120 8/02/99 9:13p Dave
289 * 119 7/30/99 10:31p Dave
290 * Added comm menu to the configurable hud files.
292 * 118 7/30/99 5:17p Andsager
293 * first fs2demo checksums
295 * 117 7/29/99 3:09p Anoop
297 * 116 7/29/99 12:05a Dave
298 * Nebula speed optimizations.
300 * 115 7/27/99 8:59a Andsager
301 * Make major, minor version consistent for all builds. Only show major
302 * and minor for launcher update window.
304 * 114 7/26/99 5:50p Dave
305 * Revised ingame join. Better? We'll see....
307 * 113 7/26/99 5:27p Andsager
308 * Add training mission as builtin to demo build
310 * 112 7/24/99 1:54p Dave
311 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
314 * 111 7/22/99 4:00p Dave
315 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
317 * 110 7/21/99 8:10p Dave
318 * First run of supernova effect.
320 * 109 7/20/99 1:49p Dave
321 * Peter Drake build. Fixed some release build warnings.
323 * 108 7/19/99 2:26p Andsager
324 * set demo multiplayer missions
326 * 107 7/18/99 5:19p Dave
327 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
329 * 106 7/16/99 1:50p Dave
330 * 8 bit aabitmaps. yay.
332 * 105 7/15/99 3:07p Dave
333 * 32 bit detection support. Mouse coord commandline.
335 * 104 7/15/99 2:13p Dave
336 * Added 32 bit detection.
338 * 103 7/15/99 9:20a Andsager
339 * FS2_DEMO initial checkin
341 * 102 7/14/99 11:02a Dave
342 * Skill level default back to easy. Blech.
344 * 101 7/09/99 5:54p Dave
345 * Seperated cruiser types into individual types. Added tons of new
346 * briefing icons. Campaign screen.
348 * 100 7/08/99 4:43p Andsager
349 * New check for sparky_hi and print if not found.
351 * 99 7/08/99 10:53a Dave
352 * New multiplayer interpolation scheme. Not 100% done yet, but still
353 * better than the old way.
355 * 98 7/06/99 4:24p Dave
356 * Mid-level checkin. Starting on some potentially cool multiplayer
359 * 97 7/06/99 3:35p Andsager
360 * Allow movie to play before red alert mission.
362 * 96 7/03/99 5:50p Dave
363 * Make rotated bitmaps draw properly in padlock views.
365 * 95 7/02/99 9:55p Dave
366 * Player engine wash sound.
368 * 94 7/02/99 4:30p Dave
369 * Much more sophisticated lightning support.
371 * 93 6/29/99 7:52p Dave
372 * Put in exception handling in FS2.
374 * 92 6/22/99 9:37p Dave
375 * Put in pof spewing.
377 * 91 6/16/99 4:06p Dave
378 * New pilot info popup. Added new draw-bitmap-as-poly function.
380 * 90 6/15/99 1:56p Andsager
381 * For release builds, allow start up in high res only with
384 * 89 6/15/99 9:34a Dave
385 * Fixed key checking in single threaded version of the stamp notification
388 * 88 6/09/99 2:55p Andsager
389 * Allow multiple asteroid subtypes (of large, medium, small) and follow
392 * 87 6/08/99 1:14a Dave
393 * Multi colored hud test.
395 * 86 6/04/99 9:52a Dave
396 * Fixed some rendering problems.
398 * 85 6/03/99 10:15p Dave
399 * Put in temporary main hall screen.
401 * 84 6/02/99 6:18p Dave
402 * Fixed TNT lockup problems! Wheeeee!
404 * 83 6/01/99 3:52p Dave
405 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
406 * dead popup, pxo find player popup, pxo private room popup.
408 * 82 5/26/99 1:28p Jasenw
409 * changed coords for loading ani
411 * 81 5/26/99 11:46a Dave
412 * Added ship-blasting lighting and made the randomization of lighting
413 * much more customizable.
415 * 80 5/24/99 5:45p Dave
416 * Added detail levels to the nebula, with a decent speedup. Split nebula
417 * lightning into its own section.
435 #include "systemvars.h"
440 #include "starfield.h"
441 #include "lighting.h"
446 #include "fireballs.h"
450 #include "floating.h"
451 #include "gamesequence.h"
453 #include "optionsmenu.h"
454 #include "playermenu.h"
455 #include "trainingmenu.h"
456 #include "techmenu.h"
459 #include "hudmessage.h"
461 #include "missiongoals.h"
462 #include "missionparse.h"
467 #include "multiutil.h"
468 #include "multimsgs.h"
472 #include "freespace.h"
473 #include "managepilot.h"
475 #include "contexthelp.h"
478 #include "missionbrief.h"
479 #include "missiondebrief.h"
481 #include "missionshipchoice.h"
483 #include "hudconfig.h"
484 #include "controlsconfig.h"
485 #include "missionmessage.h"
486 #include "missiontraining.h"
488 #include "hudtarget.h"
492 #include "eventmusic.h"
493 #include "animplay.h"
494 #include "missionweaponchoice.h"
495 #include "missionlog.h"
496 #include "audiostr.h"
498 #include "missioncampaign.h"
500 #include "missionhotkey.h"
501 #include "objectsnd.h"
502 #include "cmeasure.h"
504 #include "linklist.h"
505 #include "shockwave.h"
506 #include "afterburner.h"
511 #include "stand_gui.h"
512 #include "pcxutils.h"
513 #include "hudtargetbox.h"
514 #include "multi_xfer.h"
515 #include "hudescort.h"
516 #include "multiutil.h"
519 #include "multiteamselect.h"
522 #include "readyroom.h"
523 #include "mainhallmenu.h"
524 #include "multilag.h"
526 #include "particle.h"
528 #include "multi_ingame.h"
529 #include "snazzyui.h"
530 #include "asteroid.h"
531 #include "popupdead.h"
532 #include "multi_voice.h"
533 #include "missioncmdbrief.h"
534 #include "redalert.h"
535 #include "gameplayhelp.h"
536 #include "multilag.h"
537 #include "staticrand.h"
538 #include "multi_pmsg.h"
539 #include "levelpaging.h"
540 #include "observer.h"
541 #include "multi_pause.h"
542 #include "multi_endgame.h"
543 #include "cutscenes.h"
544 #include "multi_respawn.h"
545 // #include "movie.h"
546 #include "multi_obj.h"
547 #include "multi_log.h"
549 #include "localize.h"
550 #include "osregistry.h"
551 #include "barracks.h"
552 #include "missionpause.h"
554 #include "alphacolors.h"
555 #include "objcollide.h"
558 #include "neblightning.h"
559 #include "shipcontrails.h"
562 #include "multi_dogfight.h"
563 #include "multi_rate.h"
564 #include "muzzleflash.h"
568 #include "mainhalltemp.h"
569 #include "exceptionhandler.h"
573 #include "supernova.h"
574 #include "hudshield.h"
575 // #include "names.h"
577 #include "missionloopbrief.h"
581 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
587 // 1.00.04 5/26/98 MWA -- going final (12 pm)
588 // 1.00.03 5/26/98 MWA -- going final (3 am)
589 // 1.00.02 5/25/98 MWA -- going final
590 // 1.00.01 5/25/98 MWA -- going final
591 // 0.90 5/21/98 MWA -- getting ready for final.
592 // 0.10 4/9/98. Set by MK.
594 // Demo version: (obsolete since DEMO codebase split from tree)
595 // 0.03 4/10/98 AL. Interplay rev
596 // 0.02 4/8/98 MK. Increased when this system was modified.
597 // 0.01 4/7/98? AL. First release to Interplay QA.
600 // 1.00 5/28/98 AL. First release to Interplay QA.
602 void game_level_init(int seed = -1);
603 void game_post_level_init();
604 void game_do_frame();
605 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
606 void game_reset_time();
607 void game_show_framerate(); // draws framerate in lower right corner
609 int Game_no_clear = 0;
611 int Pofview_running = 0;
612 int Nebedit_running = 0;
614 typedef struct big_expl_flash {
615 float max_flash_intensity; // max intensity
616 float cur_flash_intensity; // cur intensity
617 int flash_start; // start time
620 #define FRAME_FILTER 16
622 #define DEFAULT_SKILL_LEVEL 1
623 int Game_skill_level = DEFAULT_SKILL_LEVEL;
625 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
626 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
628 #define EXE_FNAME ("fs2.exe")
629 #define LAUNCHER_FNAME ("freespace2.exe")
631 // JAS: Code for warphole camera.
632 // Needs to be cleaned up.
633 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
634 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
635 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
636 matrix Camera_orient = IDENTITY_MATRIX;
637 float Camera_damping = 1.0f;
638 float Camera_time = 0.0f;
639 float Warpout_time = 0.0f;
640 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
641 int Warpout_sound = -1;
643 int Use_joy_mouse = 0;
644 int Use_palette_flash = 1;
646 int Use_fullscreen_at_startup = 0;
648 int Show_area_effect = 0;
649 object *Last_view_target = NULL;
651 int dogfight_blown = 0;
654 float frametimes[FRAME_FILTER];
655 float frametotal = 0.0f;
659 int Show_framerate = 0;
661 int Show_framerate = 1;
664 int Framerate_cap = 120;
667 int Show_target_debug_info = 0;
668 int Show_target_weapons = 0;
670 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
672 int Debug_octant = -1;
674 fix Game_time_compression = F1_0;
676 // if the ships.tbl the player has is valid
677 int Game_ships_tbl_valid = 0;
679 // if the weapons.tbl the player has is valid
680 int Game_weapons_tbl_valid = 0;
684 extern int Player_attacking_enabled;
688 int Pre_player_entry;
690 int Fred_running = 0;
691 char Game_current_mission_filename[MAX_FILENAME_LEN];
692 int game_single_step = 0;
693 int last_single_step=0;
695 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
696 extern int MSG_WINDOW_Y_START;
697 extern int MSG_WINDOW_HEIGHT;
699 int game_zbuffer = 1;
700 //static int Game_music_paused;
701 static int Game_paused;
705 #define EXPIRE_BAD_CHECKSUM 1
706 #define EXPIRE_BAD_TIME 2
708 extern void ssm_init();
709 extern void ssm_level_init();
710 extern void ssm_process();
712 // static variable to contain the time this version was built
713 // commented out for now until
714 // I figure out how to get the username into the file
715 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
717 // defines and variables used for dumping frame for making trailers.
719 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
720 int Debug_dump_trigger = 0;
721 int Debug_dump_frame_count;
722 int Debug_dump_frame_num = 0;
723 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
726 // amount of time to wait after the player has died before we display the death died popup
727 #define PLAYER_DIED_POPUP_WAIT 2500
728 int Player_died_popup_wait = -1;
729 int Player_multi_died_check = -1;
731 // builtin mission list stuff
733 int Game_builtin_mission_count = 6;
734 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
735 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
736 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
737 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
738 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
739 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
740 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
742 #elif defined(PD_BUILD)
743 int Game_builtin_mission_count = 4;
744 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
745 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
746 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
747 { "sm1-01", (FSB_FROM_VOLITION), "" },
748 { "sm1-05", (FSB_FROM_VOLITION), "" },
750 #elif defined(MULTIPLAYER_BETA)
751 int Game_builtin_mission_count = 17;
752 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
754 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
755 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
756 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
757 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
758 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
759 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
760 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
761 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
762 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
763 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
764 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
765 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
766 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
767 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
768 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
769 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
770 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
772 #elif defined(OEM_BUILD)
773 int Game_builtin_mission_count = 17;
774 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
775 // oem version - act 1 only
776 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
779 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
780 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
781 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
782 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
783 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
784 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
785 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
786 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
787 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
788 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
789 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
790 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
791 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
792 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
793 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
794 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
797 int Game_builtin_mission_count = 92;
798 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
799 // single player campaign
800 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
803 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
804 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
805 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
806 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
807 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
808 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
809 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
810 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
811 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
812 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
813 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
814 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
815 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
816 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
817 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
818 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
819 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
820 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
825 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
826 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
827 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
828 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
829 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
830 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
831 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
832 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
833 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
836 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
837 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
838 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
839 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
840 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
841 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
847 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 // multiplayer missions
852 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
853 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
858 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
859 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
864 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
865 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
906 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
907 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
908 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
909 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
914 // Internal function prototypes
915 void game_maybe_draw_mouse(float frametime);
916 void init_animating_pointer();
917 void load_animating_pointer(char *filename, int dx, int dy);
918 void unload_animating_pointer();
919 void game_do_training_checks();
920 void game_shutdown(void);
921 void game_show_event_debug(float frametime);
922 void game_event_debug_init();
924 void demo_upsell_show_screens();
925 void game_start_subspace_ambient_sound();
926 void game_stop_subspace_ambient_sound();
927 void verify_ships_tbl();
928 void verify_weapons_tbl();
929 void display_title_screen();
931 // loading background filenames
932 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
933 "LoadingBG", // GR_640
934 "2_LoadingBG" // GR_1024
938 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
939 "Loading.ani", // GR_640
940 "2_Loading.ani" // GR_1024
943 #if defined(FS2_DEMO)
944 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
948 #elif defined(OEM_BUILD)
949 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
956 char Game_CDROM_dir[MAX_PATH_LEN];
959 // How much RAM is on this machine. Set in WinMain
960 uint Freespace_total_ram = 0;
963 float Game_flash_red = 0.0f;
964 float Game_flash_green = 0.0f;
965 float Game_flash_blue = 0.0f;
966 float Sun_spot = 0.0f;
967 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
969 // game shudder stuff (in ms)
970 int Game_shudder_time = -1;
971 int Game_shudder_total = 0;
972 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
975 sound_env Game_sound_env;
976 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
977 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
979 int Game_sound_env_update_timestamp;
981 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
984 // WARPIN CRAP END --------------------------------------------------------------------------------------------
986 fs_builtin_mission *game_find_builtin_mission(char *filename)
990 // look through all existing builtin missions
991 for(idx=0; idx<Game_builtin_mission_count; idx++){
992 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
993 return &Game_builtin_mission_list[idx];
1001 int game_get_default_skill_level()
1003 return DEFAULT_SKILL_LEVEL;
1007 void game_flash_reset()
1009 Game_flash_red = 0.0f;
1010 Game_flash_green = 0.0f;
1011 Game_flash_blue = 0.0f;
1013 Big_expl_flash.max_flash_intensity = 0.0f;
1014 Big_expl_flash.cur_flash_intensity = 0.0f;
1015 Big_expl_flash.flash_start = 0;
1018 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1019 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1021 void game_framerate_check_init()
1023 // zero critical time
1024 Gf_critical_time = 0.0f;
1027 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1028 // if this is a glide card
1029 if(gr_screen.mode == GR_GLIDE){
1031 extern GrHwConfiguration hwconfig;
1034 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1035 Gf_critical = 15.0f;
1039 Gf_critical = 10.0f;
1044 Gf_critical = 15.0f;
1047 // d3d. only care about good cards here I guess (TNT)
1049 Gf_critical = 15.0f;
1052 // if this is a glide card
1053 if(gr_screen.mode == GR_GLIDE){
1055 extern GrHwConfiguration hwconfig;
1058 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1059 Gf_critical = 25.0f;
1063 Gf_critical = 20.0f;
1068 Gf_critical = 25.0f;
1071 // d3d. only care about good cards here I guess (TNT)
1073 Gf_critical = 25.0f;
1078 extern float Framerate;
1079 void game_framerate_check()
1083 // if the current framerate is above the critical level, add frametime
1084 if(Framerate >= Gf_critical){
1085 Gf_critical_time += flFrametime;
1088 if(!Show_framerate){
1092 // display if we're above the critical framerate
1093 if(Framerate < Gf_critical){
1094 gr_set_color_fast(&Color_bright_red);
1095 gr_string(200, y_start, "Framerate warning");
1100 // display our current pct of good frametime
1101 if(f2fl(Missiontime) >= 0.0f){
1102 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1105 gr_set_color_fast(&Color_bright_green);
1107 gr_set_color_fast(&Color_bright_red);
1110 gr_printf(200, y_start, "%d%%", (int)pct);
1117 // Adds a flash effect. These can be positive or negative.
1118 // The range will get capped at around -1 to 1, so stick
1119 // with a range like that.
1120 void game_flash( float r, float g, float b )
1122 Game_flash_red += r;
1123 Game_flash_green += g;
1124 Game_flash_blue += b;
1126 if ( Game_flash_red < -1.0f ) {
1127 Game_flash_red = -1.0f;
1128 } else if ( Game_flash_red > 1.0f ) {
1129 Game_flash_red = 1.0f;
1132 if ( Game_flash_green < -1.0f ) {
1133 Game_flash_green = -1.0f;
1134 } else if ( Game_flash_green > 1.0f ) {
1135 Game_flash_green = 1.0f;
1138 if ( Game_flash_blue < -1.0f ) {
1139 Game_flash_blue = -1.0f;
1140 } else if ( Game_flash_blue > 1.0f ) {
1141 Game_flash_blue = 1.0f;
1146 // Adds a flash for Big Ship explosions
1147 // cap range from 0 to 1
1148 void big_explosion_flash(float flash)
1150 Big_expl_flash.flash_start = timestamp(1);
1154 } else if (flash < 0.0f) {
1158 Big_expl_flash.max_flash_intensity = flash;
1159 Big_expl_flash.cur_flash_intensity = 0.0f;
1162 // Amount to diminish palette towards normal, per second.
1163 #define DIMINISH_RATE 0.75f
1164 #define SUN_DIMINISH_RATE 6.00f
1168 float sn_glare_scale = 1.7f;
1171 dc_get_arg(ARG_FLOAT);
1172 sn_glare_scale = Dc_arg_float;
1175 float Supernova_last_glare = 0.0f;
1176 void game_sunspot_process(float frametime)
1180 float Sun_spot_goal = 0.0f;
1183 sn_stage = supernova_active();
1185 // sunspot differently based on supernova stage
1187 // approaching. player still in control
1190 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1193 light_get_global_dir(&light_dir, 0);
1195 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1198 // scale it some more
1199 dot = dot * (0.5f + (pct * 0.5f));
1202 Sun_spot_goal += (dot * sn_glare_scale);
1205 // draw the sun glow
1206 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1207 // draw the glow for this sun
1208 stars_draw_sun_glow(0);
1211 Supernova_last_glare = Sun_spot_goal;
1214 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1217 Sun_spot_goal = 0.9f;
1218 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1220 if(Sun_spot_goal > 1.0f){
1221 Sun_spot_goal = 1.0f;
1224 Sun_spot_goal *= sn_glare_scale;
1225 Supernova_last_glare = Sun_spot_goal;
1228 // fade to white. display dead popup
1231 Supernova_last_glare += (2.0f * flFrametime);
1232 if(Supernova_last_glare > 2.0f){
1233 Supernova_last_glare = 2.0f;
1236 Sun_spot_goal = Supernova_last_glare;
1243 // check sunspots for all suns
1244 n_lights = light_get_global_count();
1247 for(idx=0; idx<n_lights; idx++){
1248 //(vector *eye_pos, matrix *eye_orient)
1249 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1252 light_get_global_dir(&light_dir, idx);
1254 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1256 Sun_spot_goal += (float)pow(dot,85.0f);
1258 // draw the glow for this sun
1259 stars_draw_sun_glow(idx);
1261 Sun_spot_goal = 0.0f;
1267 Sun_spot_goal = 0.0f;
1271 float dec_amount = frametime*SUN_DIMINISH_RATE;
1273 if ( Sun_spot < Sun_spot_goal ) {
1274 Sun_spot += dec_amount;
1275 if ( Sun_spot > Sun_spot_goal ) {
1276 Sun_spot = Sun_spot_goal;
1278 } else if ( Sun_spot > Sun_spot_goal ) {
1279 Sun_spot -= dec_amount;
1280 if ( Sun_spot < Sun_spot_goal ) {
1281 Sun_spot = Sun_spot_goal;
1287 // Call once a frame to diminish the
1288 // flash effect to 0.
1289 void game_flash_diminish(float frametime)
1291 float dec_amount = frametime*DIMINISH_RATE;
1293 if ( Game_flash_red > 0.0f ) {
1294 Game_flash_red -= dec_amount;
1295 if ( Game_flash_red < 0.0f )
1296 Game_flash_red = 0.0f;
1298 Game_flash_red += dec_amount;
1299 if ( Game_flash_red > 0.0f )
1300 Game_flash_red = 0.0f;
1303 if ( Game_flash_green > 0.0f ) {
1304 Game_flash_green -= dec_amount;
1305 if ( Game_flash_green < 0.0f )
1306 Game_flash_green = 0.0f;
1308 Game_flash_green += dec_amount;
1309 if ( Game_flash_green > 0.0f )
1310 Game_flash_green = 0.0f;
1313 if ( Game_flash_blue > 0.0f ) {
1314 Game_flash_blue -= dec_amount;
1315 if ( Game_flash_blue < 0.0f )
1316 Game_flash_blue = 0.0f;
1318 Game_flash_blue += dec_amount;
1319 if ( Game_flash_blue > 0.0f )
1320 Game_flash_blue = 0.0f;
1323 // update big_explosion_cur_flash
1324 #define TIME_UP 1500
1325 #define TIME_DOWN 2500
1326 int duration = TIME_UP + TIME_DOWN;
1327 int time = timestamp_until(Big_expl_flash.flash_start);
1328 if (time > -duration) {
1330 if (time < TIME_UP) {
1331 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1334 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1338 if ( Use_palette_flash ) {
1340 // static int or=0, og=0, ob=0;
1342 // Change the 200 to change the color range of colors.
1343 r = fl2i( Game_flash_red*128.0f );
1344 g = fl2i( Game_flash_green*128.0f );
1345 b = fl2i( Game_flash_blue*128.0f );
1347 if ( Sun_spot > 0.0f ) {
1348 r += fl2i(Sun_spot*128.0f);
1349 g += fl2i(Sun_spot*128.0f);
1350 b += fl2i(Sun_spot*128.0f);
1353 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1354 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1355 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1356 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1359 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1360 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1361 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1363 if ( (r!=0) || (g!=0) || (b!=0) ) {
1364 gr_flash( r, g, b );
1366 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1377 void game_level_close()
1379 // De-Initialize the game subsystems
1380 message_mission_shutdown();
1381 event_music_level_close();
1382 game_stop_looped_sounds();
1384 obj_snd_level_close(); // uninit object-linked persistant sounds
1385 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1386 anim_level_close(); // stop and clean up any anim instances
1387 shockwave_level_close();
1388 fireball_level_close();
1390 mission_event_shutdown();
1391 asteroid_level_close();
1392 model_cache_reset(); // Reset/free all the model caching stuff
1393 flak_level_close(); // unload flak stuff
1394 neb2_level_close(); // shutdown gaseous nebula stuff
1397 mflash_level_close();
1399 audiostream_unpause_all();
1404 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1405 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1406 void game_level_init(int seed)
1408 // seed the random number generator
1410 // if no seed was passed, seed the generator either from the time value, or from the
1411 // netgame security flags -- ensures that all players in multiplayer game will have the
1412 // same randon number sequence (with static rand functions)
1413 if ( Game_mode & GM_NORMAL ) {
1414 Game_level_seed = time(NULL);
1416 Game_level_seed = Netgame.security;
1419 // mwa 9/17/98 -- maybe this assert isn't needed????
1420 Assert( !(Game_mode & GM_MULTIPLAYER) );
1421 Game_level_seed = seed;
1423 srand( Game_level_seed );
1425 // semirand function needs to get re-initted every time in multiplayer
1426 if ( Game_mode & GM_MULTIPLAYER ){
1432 Key_normal_game = (Game_mode & GM_NORMAL);
1435 Game_shudder_time = -1;
1437 // Initialize the game subsystems
1438 // timestamp_reset(); // Must be inited before everything else
1440 game_reset_time(); // resets time, and resets saved time too
1442 obj_init(); // Must be inited before the other systems
1443 model_free_all(); // Free all existing models
1444 mission_brief_common_init(); // Free all existing briefing/debriefing text
1445 weapon_level_init();
1446 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1448 player_level_init();
1449 shipfx_flash_init(); // Init the ship gun flash system.
1450 game_flash_reset(); // Reset the flash effect
1451 particle_init(); // Reset the particle system
1455 shield_hit_init(); // Initialize system for showing shield hits
1456 radar_mission_init();
1457 mission_init_goals();
1460 obj_snd_level_init(); // init object-linked persistant sounds
1462 shockwave_level_init();
1463 afterburner_level_init();
1464 scoring_level_init( &Player->stats );
1466 asteroid_level_init();
1467 control_config_clear_used_status();
1468 collide_ship_ship_sounds_init();
1470 Pre_player_entry = 1; // Means the player has not yet entered.
1471 Entry_delay_time = 0; // Could get overwritten in mission read.
1472 fireball_preload(); // page in warphole bitmaps
1474 flak_level_init(); // initialize flak - bitmaps, etc
1475 ct_level_init(); // initialize ships contrails, etc
1476 awacs_level_init(); // initialize AWACS
1477 beam_level_init(); // initialize beam weapons
1478 mflash_level_init();
1480 supernova_level_init();
1482 // multiplayer dogfight hack
1485 shipfx_engine_wash_level_init();
1489 Last_view_target = NULL;
1494 // campaign wasn't ended
1495 Campaign_ended_in_mission = 0;
1498 // called when a mission is over -- does server specific stuff.
1499 void freespace_stop_mission()
1502 Game_mode &= ~GM_IN_MISSION;
1505 // called at frame interval to process networking stuff
1506 void game_do_networking()
1508 Assert( Net_player != NULL );
1509 if (!(Game_mode & GM_MULTIPLAYER)){
1513 // see if this player should be reading/writing data. Bit is set when at join
1514 // screen onward until quits back to main menu.
1515 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1519 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1522 multi_pause_do_frame();
1527 // Loads the best palette for this level, based
1528 // on nebula color and hud color. You could just call palette_load_table with
1529 // the appropriate filename, but who wants to do that.
1530 void game_load_palette()
1532 char palette_filename[1024];
1534 // We only use 3 hud colors right now
1535 // Assert( HUD_config.color >= 0 );
1536 // Assert( HUD_config.color <= 2 );
1538 Assert( Mission_palette >= 0 );
1539 Assert( Mission_palette <= 98 );
1541 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1542 strcpy( palette_filename, NOX("gamepalette-subspace") );
1544 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1547 mprintf(( "Loading palette %s\n", palette_filename ));
1549 // palette_load_table(palette_filename);
1552 void game_post_level_init()
1554 // Stuff which gets called after mission is loaded. Because player isn't created until
1555 // after mission loads, some things must get initted after the level loads
1557 model_level_post_init();
1560 hud_setup_escort_list();
1561 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1567 game_event_debug_init();
1570 training_mission_init();
1571 asteroid_create_all();
1573 game_framerate_check_init();
1577 // An estimate as to how high the count passed to game_loading_callback will go.
1578 // This is just a guess, it seems to always be about the same. The count is
1579 // proportional to the code being executed, not the time, so this works good
1580 // for a bar, assuming the code does about the same thing each time you
1581 // load a level. You can find this value by looking at the return value
1582 // of game_busy_callback(NULL), which I conveniently print out to the
1583 // debug output window with the '=== ENDING LOAD ==' stuff.
1584 //#define COUNT_ESTIMATE 3706
1585 #define COUNT_ESTIMATE 1111
1587 int Game_loading_callback_inited = 0;
1589 int Game_loading_background = -1;
1590 anim * Game_loading_ani = NULL;
1591 anim_instance *Game_loading_ani_instance;
1592 int Game_loading_frame=-1;
1594 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1603 // This gets called 10x per second and count is the number of times
1604 // game_busy() has been called since the current callback function
1606 void game_loading_callback(int count)
1608 game_do_networking();
1610 Assert( Game_loading_callback_inited==1 );
1611 Assert( Game_loading_ani != NULL );
1613 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1614 if ( framenum > Game_loading_ani->total_frames-1 ) {
1615 framenum = Game_loading_ani->total_frames-1;
1616 } else if ( framenum < 0 ) {
1621 while ( Game_loading_frame < framenum ) {
1622 Game_loading_frame++;
1623 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1627 if ( cbitmap > -1 ) {
1628 if ( Game_loading_background > -1 ) {
1629 gr_set_bitmap( Game_loading_background );
1633 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1634 gr_set_bitmap( cbitmap );
1635 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1637 bm_release(cbitmap);
1643 void game_loading_callback_init()
1645 Assert( Game_loading_callback_inited==0 );
1647 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1648 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1651 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1652 Assert( Game_loading_ani != NULL );
1653 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1654 Assert( Game_loading_ani_instance != NULL );
1655 Game_loading_frame = -1;
1657 Game_loading_callback_inited = 1;
1659 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1664 void game_loading_callback_close()
1666 Assert( Game_loading_callback_inited==1 );
1668 // Make sure bar shows all the way over.
1669 game_loading_callback(COUNT_ESTIMATE);
1671 int real_count = game_busy_callback( NULL );
1674 Game_loading_callback_inited = 0;
1677 mprintf(( "=================== ENDING LOAD ================\n" ));
1678 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1679 mprintf(( "================================================\n" ));
1681 // to remove warnings in release build
1685 free_anim_instance(Game_loading_ani_instance);
1686 Game_loading_ani_instance = NULL;
1687 anim_free(Game_loading_ani);
1688 Game_loading_ani = NULL;
1690 bm_release( Game_loading_background );
1691 common_free_interface_palette(); // restore game palette
1692 Game_loading_background = -1;
1694 gr_set_font( FONT1 );
1697 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1699 void game_maybe_update_sound_environment()
1701 // do nothing for now
1704 // Assign the sound environment for the game, based on the current mission
1706 void game_assign_sound_environment()
1709 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1710 Game_sound_env.id = SND_ENV_DRUGGED;
1711 Game_sound_env.volume = 0.800f;
1712 Game_sound_env.damping = 1.188f;
1713 Game_sound_env.decay = 6.392f;
1715 } else if (Num_asteroids > 30) {
1716 Game_sound_env.id = SND_ENV_AUDITORIUM;
1717 Game_sound_env.volume = 0.603f;
1718 Game_sound_env.damping = 0.5f;
1719 Game_sound_env.decay = 4.279f;
1722 Game_sound_env = Game_default_sound_env;
1726 Game_sound_env = Game_default_sound_env;
1727 Game_sound_env_update_timestamp = timestamp(1);
1730 // function which gets called before actually entering the mission. It is broken down into a funciton
1731 // since it will get called in one place from a single player game and from another place for
1732 // a multiplayer game
1733 void freespace_mission_load_stuff()
1735 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1736 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1737 if(!(Game_mode & GM_STANDALONE_SERVER)){
1739 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1741 game_loading_callback_init();
1743 event_music_level_init(); // preloads the first 2 seconds for each event music track
1746 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1749 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1752 ship_assign_sound_all(); // assign engine sounds to ships
1753 game_assign_sound_environment(); // assign the sound environment for this mission
1756 // call function in missionparse.cpp to fixup player/ai stuff.
1757 mission_parse_fixup_players();
1760 // Load in all the bitmaps for this level
1765 game_loading_callback_close();
1767 // the only thing we need to call on the standalone for now.
1769 // call function in missionparse.cpp to fixup player/ai stuff.
1770 mission_parse_fixup_players();
1772 // Load in all the bitmaps for this level
1778 uint load_mission_load;
1779 uint load_post_level_init;
1780 uint load_mission_stuff;
1782 // tells the server to load the mission and initialize structures
1783 int game_start_mission()
1785 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1787 load_gl_init = time(NULL);
1789 load_gl_init = time(NULL) - load_gl_init;
1791 if (Game_mode & GM_MULTIPLAYER) {
1792 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1794 // clear multiplayer stats
1795 init_multiplayer_stats();
1798 load_mission_load = time(NULL);
1799 if (mission_load()) {
1800 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1801 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1802 gameseq_post_event(GS_EVENT_MAIN_MENU);
1804 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1809 load_mission_load = time(NULL) - load_mission_load;
1811 // If this is a red alert mission in campaign mode, bash wingman status
1812 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1813 red_alert_bash_wingman_status();
1816 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1817 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1818 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1819 // game_load_palette();
1822 load_post_level_init = time(NULL);
1823 game_post_level_init();
1824 load_post_level_init = time(NULL) - load_post_level_init;
1828 void Do_model_timings_test();
1829 Do_model_timings_test();
1833 load_mission_stuff = time(NULL);
1834 freespace_mission_load_stuff();
1835 load_mission_stuff = time(NULL) - load_mission_stuff;
1840 int Interface_framerate = 0;
1843 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1844 DCF_BOOL( show_framerate, Show_framerate )
1845 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1846 DCF_BOOL( show_target_weapons, Show_target_weapons )
1847 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1848 DCF_BOOL( sound, Sound_enabled )
1849 DCF_BOOL( zbuffer, game_zbuffer )
1850 DCF_BOOL( shield_system, New_shield_system )
1851 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1852 DCF_BOOL( player_attacking, Player_attacking_enabled )
1853 DCF_BOOL( show_waypoints, Show_waypoints )
1854 DCF_BOOL( show_area_effect, Show_area_effect )
1855 DCF_BOOL( show_net_stats, Show_net_stats )
1856 DCF_BOOL( log, Log_debug_output_to_file )
1857 DCF_BOOL( training_msg_method, Training_msg_method )
1858 DCF_BOOL( show_player_pos, Show_player_pos )
1859 DCF_BOOL(i_framerate, Interface_framerate )
1861 DCF(show_mem,"Toggles showing mem usage")
1864 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1865 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1866 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1867 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1873 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1875 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1876 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1880 DCF(show_cpu,"Toggles showing cpu usage")
1883 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1884 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1885 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1886 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1892 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1894 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1895 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1902 // AL 4-8-98: always allow players to display their framerate
1905 DCF_BOOL( show_framerate, Show_framerate )
1912 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1915 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1916 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1917 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1918 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1920 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" );
1921 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1923 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1926 DCF(palette_flash,"Toggles palette flash effect on/off")
1929 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1930 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1931 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1932 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1934 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1935 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1938 int Use_low_mem = 0;
1940 DCF(low_mem,"Uses low memory settings regardless of RAM")
1943 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1944 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1945 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1946 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1948 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1949 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1951 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1957 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1960 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1961 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1962 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1963 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1965 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1966 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1967 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1971 int Framerate_delay = 0;
1973 float Freespace_gamma = 1.0f;
1975 DCF(gamma,"Sets Gamma factor")
1978 dc_get_arg(ARG_FLOAT|ARG_NONE);
1979 if ( Dc_arg_type & ARG_FLOAT ) {
1980 Freespace_gamma = Dc_arg_float;
1982 dc_printf( "Gamma reset to 1.0f\n" );
1983 Freespace_gamma = 1.0f;
1985 if ( Freespace_gamma < 0.1f ) {
1986 Freespace_gamma = 0.1f;
1987 } else if ( Freespace_gamma > 5.0f ) {
1988 Freespace_gamma = 5.0f;
1990 gr_set_gamma(Freespace_gamma);
1992 char tmp_gamma_string[32];
1993 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1994 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1998 dc_printf( "Usage: gamma <float>\n" );
1999 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2000 Dc_status = 0; // don't print status if help is printed. Too messy.
2004 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2013 Game_current_mission_filename[0] = 0;
2015 // seed the random number generator
2016 Game_init_seed = time(NULL);
2017 srand( Game_init_seed );
2019 Framerate_delay = 0;
2025 extern void bm_init();
2031 // Initialize the timer before the os
2039 GetCurrentDirectory(1024, whee);
2045 strcat(whee, EXE_FNAME);
2047 //Initialize the libraries
2048 s1 = timer_get_milliseconds();
2049 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2052 e1 = timer_get_milliseconds();
2054 // time a bunch of cfopens
2056 s2 = timer_get_milliseconds();
2058 for(int idx=0; idx<10000; idx++){
2059 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2064 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2066 e2 = timer_get_milliseconds();
2069 if (Is_standalone) {
2070 std_init_standalone();
2072 os_init( Osreg_class_name, Osreg_app_name );
2073 os_set_title(Osreg_title);
2076 // initialize localization module. Make sure this is down AFTER initialzing OS.
2077 // int t1 = timer_get_milliseconds();
2080 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2082 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2085 // verify that he has a valid weapons.tbl
2086 verify_weapons_tbl();
2088 // Output version numbers to registry for auto patching purposes
2089 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2090 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2091 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2093 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2094 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2095 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2098 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2102 Asteroids_enabled = 1;
2105 /////////////////////////////
2107 /////////////////////////////
2112 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2113 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2115 if (!stricmp(ptr, NOX("no sound"))) {
2116 Cmdline_freespace_no_sound = 1;
2118 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2120 } else if (!stricmp(ptr, NOX("EAX"))) {
2125 if (!Is_standalone) {
2126 snd_init(use_a3d, use_eax);
2128 /////////////////////////////
2130 /////////////////////////////
2132 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2135 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);
2137 // fire up the UpdateLauncher executable
2139 PROCESS_INFORMATION pi;
2141 memset( &si, 0, sizeof(STARTUPINFO) );
2144 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2145 NULL, // pointer to command line string
2146 NULL, // pointer to process security attributes
2147 NULL, // pointer to thread security attributes
2148 FALSE, // handle inheritance flag
2149 CREATE_DEFAULT_ERROR_MODE, // creation flags
2150 NULL, // pointer to new environment block
2151 NULL, // pointer to current directory name
2152 &si, // pointer to STARTUPINFO
2153 &pi // pointer to PROCESS_INFORMATION
2156 // If the Launcher could not be started up, let the user know
2158 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2167 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2169 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);
2177 // check for hi res pack file
2178 int has_sparky_hi = 0;
2180 // check if sparky_hi exists -- access mode 0 means does file exist
2183 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2186 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2189 // see if we've got 32 bit in the string
2190 if(strstr(ptr, "32 bit")){
2196 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2198 // always 640 for E3
2199 gr_init(GR_640, GR_GLIDE);
2201 // regular or hi-res ?
2203 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2205 if(strstr(ptr, NOX("(1024x768)"))){
2207 gr_init(GR_1024, GR_GLIDE);
2209 gr_init(GR_640, GR_GLIDE);
2212 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2214 // always 640 for E3
2216 gr_init(GR_640, GR_DIRECT3D, depth);
2218 // regular or hi-res ?
2220 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2222 if(strstr(ptr, NOX("(1024x768)"))){
2226 gr_init(GR_1024, GR_DIRECT3D, depth);
2230 gr_init(GR_640, GR_DIRECT3D, depth);
2236 if ( Use_fullscreen_at_startup && !Is_standalone) {
2237 gr_init(GR_640, GR_DIRECTDRAW);
2239 gr_init(GR_640, GR_SOFTWARE);
2242 if ( !Is_standalone ) {
2243 gr_init(GR_640, GR_DIRECTDRAW);
2245 gr_init(GR_640, GR_SOFTWARE);
2251 extern int Gr_inited;
2252 if(trying_d3d && !Gr_inited){
2253 extern char Device_init_error[512];
2255 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2264 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2265 Freespace_gamma = (float)atof(ptr);
2266 if ( Freespace_gamma < 0.1f ) {
2267 Freespace_gamma = 0.1f;
2268 } else if ( Freespace_gamma > 5.0f ) {
2269 Freespace_gamma = 5.0f;
2271 char tmp_gamma_string[32];
2272 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2273 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2275 gr_set_gamma(Freespace_gamma);
2277 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2280 display_title_screen();
2284 // attempt to load up master tracker registry info (login and password)
2285 Multi_tracker_id = -1;
2287 // pxo login and password
2288 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2290 nprintf(("Network","Error reading in PXO login data\n"));
2291 strcpy(Multi_tracker_login,"");
2293 strcpy(Multi_tracker_login,ptr);
2295 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2297 nprintf(("Network","Error reading PXO password\n"));
2298 strcpy(Multi_tracker_passwd,"");
2300 strcpy(Multi_tracker_passwd,ptr);
2303 // pxo squad name and password
2304 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2306 nprintf(("Network","Error reading in PXO squad name\n"));
2307 strcpy(Multi_tracker_squad_name, "");
2309 strcpy(Multi_tracker_squad_name, ptr);
2312 // If less than 48MB of RAM, use low memory model.
2313 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2314 mprintf(( "Using normal memory settings...\n" ));
2315 bm_set_low_mem(1); // Use every other frame of bitmaps
2317 mprintf(( "Using high memory settings...\n" ));
2318 bm_set_low_mem(0); // Use all frames of bitmaps
2321 // load non-darkening pixel defs
2322 palman_load_pixels();
2324 // hud shield icon stuff
2325 hud_shield_game_init();
2327 control_config_common_init(); // sets up localization stuff in the control config
2333 gamesnd_parse_soundstbl();
2338 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2343 player_controls_init();
2346 //if(!Is_standalone){
2354 ship_init(); // read in ships.tbl
2356 mission_campaign_init(); // load in the default campaign
2358 // navmap_init(); // init the navigation map system
2359 context_help_init();
2360 techroom_intel_init(); // parse species.tbl, load intel info
2362 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2363 init_animating_pointer();
2365 mission_brief_common_init(); // Mark all the briefing structures as empty.
2366 gr_font_init(); // loads up all fonts
2368 neb2_init(); // fullneb stuff
2372 player_tips_init(); // helpful tips
2375 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2376 pilot_load_pic_list();
2377 pilot_load_squad_pic_list();
2379 load_animating_pointer(NOX("cursor"), 0, 0);
2381 // initialize alpha colors
2382 alpha_colors_init();
2385 // Game_music_paused = 0;
2392 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2393 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2395 mprintf(("cfile_init() took %d\n", e1 - s1));
2396 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2399 char transfer_text[128];
2401 float Start_time = 0.0f;
2403 float Framerate = 0.0f;
2405 float Timing_total = 0.0f;
2406 float Timing_render2 = 0.0f;
2407 float Timing_render3 = 0.0f;
2408 float Timing_flip = 0.0f;
2409 float Timing_clear = 0.0f;
2411 MONITOR(NumPolysDrawn);
2417 void game_get_framerate()
2419 char text[128] = "";
2421 if ( frame_int == -1 ) {
2423 for (i=0; i<FRAME_FILTER; i++ ) {
2424 frametimes[i] = 0.0f;
2429 frametotal -= frametimes[frame_int];
2430 frametotal += flFrametime;
2431 frametimes[frame_int] = flFrametime;
2432 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2434 if ( frametotal != 0.0 ) {
2435 if ( Framecount >= FRAME_FILTER )
2436 Framerate = FRAME_FILTER / frametotal;
2438 Framerate = Framecount / frametotal;
2439 sprintf( text, NOX("FPS: %.1f"), Framerate );
2441 sprintf( text, NOX("FPS: ?") );
2445 if (Show_framerate) {
2446 gr_set_color_fast(&HUD_color_debug);
2447 gr_string( 570, 2, text );
2451 void game_show_framerate()
2455 cur_time = f2fl(timer_get_approx_seconds());
2456 if (cur_time - Start_time > 30.0f) {
2457 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2458 Start_time += 1000.0f;
2461 //mprintf(( "%s\n", text ));
2464 if ( Debug_dump_frames )
2468 // possibly show control checking info
2469 control_check_indicate();
2471 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2472 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2473 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2474 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2477 if ( Show_cpu == 1 ) {
2482 dy = gr_get_font_height() + 1;
2484 gr_set_color_fast(&HUD_color_debug);
2488 extern int D3D_textures_in;
2489 extern int D3D_textures_in_frame;
2490 extern int Glide_textures_in;
2491 extern int Glide_textures_in_frame;
2492 extern int Glide_explosion_vram;
2493 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2495 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2497 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2503 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2505 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2507 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2509 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2511 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2516 extern int Num_pairs; // Number of object pairs that were checked.
2517 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2520 extern int Num_pairs_checked; // What percent of object pairs were checked.
2521 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2523 Num_pairs_checked = 0;
2527 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2530 if ( Timing_total > 0.01f ) {
2531 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2533 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2535 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2537 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2539 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2549 dy = gr_get_font_height() + 1;
2551 gr_set_color_fast(&HUD_color_debug);
2554 extern int TotalRam;
2555 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2560 extern int Model_ram;
2561 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2565 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2567 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2569 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2573 extern int D3D_textures_in;
2574 extern int Glide_textures_in;
2575 extern int Glide_textures_in_frame;
2576 extern int Glide_explosion_vram;
2577 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2579 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2581 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2590 if ( Show_player_pos ) {
2594 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));
2597 MONITOR_INC(NumPolys, modelstats_num_polys);
2598 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2599 MONITOR_INC(NumVerts, modelstats_num_verts );
2601 modelstats_num_polys = 0;
2602 modelstats_num_polys_drawn = 0;
2603 modelstats_num_verts = 0;
2604 modelstats_num_sortnorms = 0;
2608 void game_show_standalone_framerate()
2610 float frame_rate=30.0f;
2611 if ( frame_int == -1 ) {
2613 for (i=0; i<FRAME_FILTER; i++ ) {
2614 frametimes[i] = 0.0f;
2619 frametotal -= frametimes[frame_int];
2620 frametotal += flFrametime;
2621 frametimes[frame_int] = flFrametime;
2622 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2624 if ( frametotal != 0.0 ) {
2625 if ( Framecount >= FRAME_FILTER ){
2626 frame_rate = FRAME_FILTER / frametotal;
2628 frame_rate = Framecount / frametotal;
2631 std_set_standalone_fps(frame_rate);
2635 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2636 void game_show_time_left()
2640 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2641 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2642 // checking how much time is left
2644 if ( Mission_end_time == -1 ){
2648 diff = f2i(Mission_end_time - Missiontime);
2649 // be sure to bash to 0. diff could be negative on frame that we quit mission
2654 hud_set_default_color();
2655 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2658 //========================================================================================
2659 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2660 //========================================================================================
2664 DCF(ai_pause,"Pauses ai")
2667 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2668 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2669 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2670 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2673 obj_init_all_ships_physics();
2676 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2677 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2680 DCF(single_step,"Single steps the game")
2683 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2684 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2685 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2686 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2688 last_single_step = 0; // Make so single step waits a frame before stepping
2691 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2692 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2695 DCF_BOOL(physics_pause, physics_paused)
2696 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2697 DCF_BOOL(ai_firing, Ai_firing_enabled )
2699 // Create some simple aliases to these commands...
2700 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2701 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2702 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2703 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2704 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2707 //========================================================================================
2708 //========================================================================================
2711 void game_training_pause_do()
2715 key = game_check_key();
2717 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2724 void game_increase_skill_level()
2727 if (Game_skill_level >= NUM_SKILL_LEVELS){
2728 Game_skill_level = 0;
2732 int Player_died_time;
2734 int View_percent = 100;
2737 DCF(view, "Sets the percent of the 3d view to render.")
2740 dc_get_arg(ARG_INT);
2741 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2742 View_percent = Dc_arg_int;
2744 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2750 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2754 dc_printf("View is set to %d%%\n", View_percent );
2759 // Set the clip region for the 3d rendering window
2760 void game_set_view_clip()
2762 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2763 // Set the clip region for the letterbox "dead view"
2764 int yborder = gr_screen.max_h/4;
2766 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2767 // J.S. I've changed my ways!! See the new "no constants" code!!!
2768 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2770 // Set the clip region for normal view
2771 if ( View_percent >= 100 ) {
2774 int xborder, yborder;
2776 if ( View_percent < 5 ) {
2780 float fp = i2fl(View_percent)/100.0f;
2781 int fi = fl2i(fl_sqrt(fp)*100.0f);
2782 if ( fi > 100 ) fi=100;
2784 xborder = ( gr_screen.max_w*(100-fi) )/200;
2785 yborder = ( gr_screen.max_h*(100-fi) )/200;
2787 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2793 void show_debug_stuff()
2796 int laser_count = 0, missile_count = 0;
2798 for (i=0; i<MAX_OBJECTS; i++) {
2799 if (Objects[i].type == OBJ_WEAPON){
2800 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2802 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2808 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2811 extern int Tool_enabled;
2816 int tst_bitmap = -1;
2818 float tst_offset, tst_offset_total;
2821 void game_tst_frame_pre()
2829 g3_rotate_vertex(&v, &tst_pos);
2830 g3_project_vertex(&v);
2833 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2837 // big ship? always tst
2839 // within 3000 meters
2840 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2844 // within 300 meters
2845 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2852 void game_tst_frame()
2862 tst_time = time(NULL);
2864 // load the tst bitmap
2865 switch((int)frand_range(0.0f, 3.0)){
2867 tst_bitmap = bm_load("ig_jim");
2869 mprintf(("TST 0\n"));
2873 tst_bitmap = bm_load("ig_kan");
2875 mprintf(("TST 1\n"));
2879 tst_bitmap = bm_load("ig_jim");
2881 mprintf(("TST 2\n"));
2885 tst_bitmap = bm_load("ig_kan");
2887 mprintf(("TST 3\n"));
2896 // get the tst bitmap dimensions
2898 bm_get_info(tst_bitmap, &w, &h);
2901 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2903 snd_play(&Snds[SND_VASUDAN_BUP]);
2905 // tst x and direction
2909 tst_offset_total = (float)w;
2910 tst_offset = (float)w;
2912 tst_x = (float)gr_screen.max_w;
2913 tst_offset_total = (float)-w;
2914 tst_offset = (float)w;
2922 float diff = (tst_offset_total / 0.5f) * flFrametime;
2928 tst_offset -= fl_abs(diff);
2929 } else if(tst_mode == 2){
2932 tst_offset -= fl_abs(diff);
2936 gr_set_bitmap(tst_bitmap);
2937 gr_bitmap((int)tst_x, (int)tst_y);
2940 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2944 // if we passed the switch point
2945 if(tst_offset <= 0.0f){
2950 tst_stamp = timestamp(1000);
2951 tst_offset = fl_abs(tst_offset_total);
2962 void game_tst_mark(object *objp, ship *shipp)
2971 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2974 sip = &Ship_info[shipp->ship_info_index];
2981 tst_pos = objp->pos;
2982 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2988 extern void render_shields();
2990 void player_repair_frame(float frametime)
2992 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2994 for(idx=0;idx<MAX_PLAYERS;idx++){
2997 np = &Net_players[idx];
2999 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)){
3001 // don't rearm/repair if the player is dead or dying/departing
3002 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3003 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3008 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3009 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3015 #define NUM_FRAMES_TEST 300
3016 #define NUM_MIXED_SOUNDS 16
3017 void do_timing_test(float flFrametime)
3019 static int framecount = 0;
3020 static int test_running = 0;
3021 static float test_time = 0.0f;
3023 static int snds[NUM_MIXED_SOUNDS];
3026 if ( test_running ) {
3028 test_time += flFrametime;
3029 if ( framecount >= NUM_FRAMES_TEST ) {
3031 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3032 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3037 if ( Test_begin == 1 ) {
3043 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3046 // start looping digital sounds
3047 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3048 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3055 DCF(dcf_fov, "Change the field of view")
3058 dc_get_arg(ARG_FLOAT|ARG_NONE);
3059 if ( Dc_arg_type & ARG_NONE ) {
3060 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3061 dc_printf( "Zoom factor reset\n" );
3063 if ( Dc_arg_type & ARG_FLOAT ) {
3064 if (Dc_arg_float < 0.25f) {
3065 Viewer_zoom = 0.25f;
3066 dc_printf("Zoom factor pinned at 0.25.\n");
3067 } else if (Dc_arg_float > 1.25f) {
3068 Viewer_zoom = 1.25f;
3069 dc_printf("Zoom factor pinned at 1.25.\n");
3071 Viewer_zoom = Dc_arg_float;
3077 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3080 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3084 DCF(framerate_cap, "Sets the framerate cap")
3087 dc_get_arg(ARG_INT);
3088 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3089 Framerate_cap = Dc_arg_int;
3091 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3097 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3098 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3099 dc_printf("[n] must be from 1 to 120.\n");
3103 if ( Framerate_cap )
3104 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3106 dc_printf("There is no framerate cap currently active.\n");
3110 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3111 int Show_viewing_from_self = 0;
3113 void say_view_target()
3115 object *view_target;
3117 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3118 view_target = &Objects[Player_ai->target_objnum];
3120 view_target = Player_obj;
3122 if (Game_mode & GM_DEAD) {
3123 if (Player_ai->target_objnum != -1)
3124 view_target = &Objects[Player_ai->target_objnum];
3127 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3128 if (view_target != Player_obj){
3130 char *view_target_name = NULL;
3131 switch(Objects[Player_ai->target_objnum].type) {
3133 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3136 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3137 Viewer_mode &= ~VM_OTHER_SHIP;
3139 case OBJ_JUMP_NODE: {
3140 char jump_node_name[128];
3141 strcpy(jump_node_name, XSTR( "jump node", 184));
3142 view_target_name = jump_node_name;
3143 Viewer_mode &= ~VM_OTHER_SHIP;
3152 if ( view_target_name ) {
3153 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3154 Show_viewing_from_self = 1;
3157 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3158 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3159 Show_viewing_from_self = 1;
3161 if (Show_viewing_from_self)
3162 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3167 Last_view_target = view_target;
3171 float Game_hit_x = 0.0f;
3172 float Game_hit_y = 0.0f;
3174 // Reset at the beginning of each frame
3175 void game_whack_reset()
3181 // Apply a 2d whack to the player
3182 void game_whack_apply( float x, float y )
3184 // Do some force feedback
3185 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3191 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3194 // call to apply a "shudder"
3195 void game_shudder_apply(int time, float intensity)
3197 Game_shudder_time = timestamp(time);
3198 Game_shudder_total = time;
3199 Game_shudder_intensity = intensity;
3202 #define FF_SCALE 10000
3203 void apply_hud_shake(matrix *eye_orient)
3205 if (Viewer_obj == Player_obj) {
3206 physics_info *pi = &Player_obj->phys_info;
3214 // Make eye shake due to afterburner
3215 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3218 dtime = timestamp_until(pi->afterburner_decay);
3222 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3223 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3226 // Make eye shake due to engine wash
3228 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3231 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3232 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3234 // get the intensity
3235 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3239 vm_vec_rand_vec_quick(&rand_vec);
3242 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3246 // make hud shake due to shuddering
3247 if(Game_shudder_time != -1){
3248 // if the timestamp has elapsed
3249 if(timestamp_elapsed(Game_shudder_time)){
3250 Game_shudder_time = -1;
3252 // otherwise apply some shudder
3256 dtime = timestamp_until(Game_shudder_time);
3260 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));
3261 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));
3266 vm_angles_2_matrix(&tm, &tangles);
3267 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3268 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3269 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3270 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3275 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3277 // Player's velocity just before he blew up. Used to keep camera target moving.
3278 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3280 // Set eye_pos and eye_orient based on view mode.
3281 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3285 static int last_Viewer_mode = 0;
3286 static int last_Game_mode = 0;
3287 static int last_Viewer_objnum = -1;
3289 // This code is supposed to detect camera "cuts"... like going between
3292 // determine if we need to regenerate the nebula
3293 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3294 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3295 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3296 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3297 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3298 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3299 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3300 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3301 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3304 // regenerate the nebula
3308 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3309 //mprintf(( "************** Camera cut! ************\n" ));
3310 last_Viewer_mode = Viewer_mode;
3311 last_Game_mode = Game_mode;
3313 // Camera moved. Tell stars & debris to not do blurring.
3319 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3320 player_display_packlock_view();
3323 game_set_view_clip();
3325 if (Game_mode & GM_DEAD) {
3326 vector vec_to_deader, view_pos;
3329 Viewer_mode |= VM_DEAD_VIEW;
3331 if (Player_ai->target_objnum != -1) {
3332 int view_from_player = 1;
3334 if (Viewer_mode & VM_OTHER_SHIP) {
3335 // View from target.
3336 Viewer_obj = &Objects[Player_ai->target_objnum];
3338 last_Viewer_objnum = Player_ai->target_objnum;
3340 if ( Viewer_obj->type == OBJ_SHIP ) {
3341 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3342 view_from_player = 0;
3345 last_Viewer_objnum = -1;
3348 if ( view_from_player ) {
3349 // View target from player ship.
3351 *eye_pos = Player_obj->pos;
3352 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3353 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3356 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3358 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3359 dist += flFrametime * 16.0f;
3361 vm_vec_scale(&vec_to_deader, -dist);
3362 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3364 view_pos = Player_obj->pos;
3366 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3367 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3368 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3369 Dead_player_last_vel = Player_obj->phys_info.vel;
3370 //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));
3371 } else if (Player_ai->target_objnum != -1) {
3372 view_pos = Objects[Player_ai->target_objnum].pos;
3374 // Make camera follow explosion, but gradually slow down.
3375 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3376 view_pos = Player_obj->pos;
3377 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3378 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3381 *eye_pos = Dead_camera_pos;
3383 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3385 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3390 // if supernova shockwave
3391 if(supernova_camera_cut()){
3395 // call it dead view
3396 Viewer_mode |= VM_DEAD_VIEW;
3398 // set eye pos and orient
3399 supernova_set_view(eye_pos, eye_orient);
3401 // If already blown up, these other modes can override.
3402 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3403 Viewer_mode &= ~VM_DEAD_VIEW;
3405 Viewer_obj = Player_obj;
3407 if (Viewer_mode & VM_OTHER_SHIP) {
3408 if (Player_ai->target_objnum != -1){
3409 Viewer_obj = &Objects[Player_ai->target_objnum];
3410 last_Viewer_objnum = Player_ai->target_objnum;
3412 Viewer_mode &= ~VM_OTHER_SHIP;
3413 last_Viewer_objnum = -1;
3416 last_Viewer_objnum = -1;
3419 if (Viewer_mode & VM_EXTERNAL) {
3422 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3423 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3425 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3427 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3428 vm_vec_normalize(&eye_dir);
3429 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3432 // Modify the orientation based on head orientation.
3433 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3435 } else if ( Viewer_mode & VM_CHASE ) {
3438 if ( Viewer_obj->phys_info.speed < 0.1 )
3439 move_dir = Viewer_obj->orient.fvec;
3441 move_dir = Viewer_obj->phys_info.vel;
3442 vm_vec_normalize(&move_dir);
3445 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3446 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3447 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3448 vm_vec_normalize(&eye_dir);
3450 // JAS: I added the following code because if you slew up using
3451 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3452 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3453 // call because the up and the forward vector are the same. I fixed
3454 // it by adding in a fraction of the right vector all the time to the
3456 vector tmp_up = Viewer_obj->orient.uvec;
3457 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3459 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3462 // Modify the orientation based on head orientation.
3463 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3464 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3465 *eye_pos = Camera_pos;
3467 ship * shipp = &Ships[Player_obj->instance];
3469 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3470 vm_vec_normalize(&eye_dir);
3471 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3474 // get an eye position based upon the correct type of object
3475 switch(Viewer_obj->type){
3477 // make a call to get the eye point for the player object
3478 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3481 // make a call to get the eye point for the player object
3482 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3488 #ifdef JOHNS_DEBUG_CODE
3489 john_debug_stuff(&eye_pos, &eye_orient);
3495 apply_hud_shake(eye_orient);
3497 // setup neb2 rendering
3498 neb2_render_setup(eye_pos, eye_orient);
3502 extern void ai_debug_render_stuff();
3505 int Game_subspace_effect = 0;
3506 DCF_BOOL( subspace, Game_subspace_effect );
3508 // Does everything needed to render a frame
3509 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3513 g3_start_frame(game_zbuffer);
3514 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3516 // maybe offset the HUD (jitter stuff)
3517 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3518 HUD_set_offsets(Viewer_obj, !dont_offset);
3520 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3521 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3522 // must be done before ships are rendered
3523 if ( MULTIPLAYER_CLIENT ) {
3524 shield_point_multi_setup();
3527 if ( Game_subspace_effect ) {
3528 stars_draw(0,0,0,1);
3530 stars_draw(1,1,1,0);
3533 obj_render_all(obj_render);
3534 beam_render_all(); // render all beam weapons
3535 particle_render_all(); // render particles after everything else.
3536 trail_render_all(); // render missilie trails after everything else.
3537 mflash_render_all(); // render all muzzle flashes
3539 // Why do we not show the shield effect in these modes? Seems ok.
3540 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3544 // render nebula lightning
3547 // render local player nebula
3548 neb2_render_player();
3551 ai_debug_render_stuff();
3554 #ifndef RELEASE_REAL
3555 // game_framerate_check();
3559 extern void snd_spew_debug_info();
3560 snd_spew_debug_info();
3563 //================ END OF 3D RENDERING STUFF ====================
3567 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3568 hud_maybe_clear_head_area();
3569 anim_render_all(0, flFrametime);
3572 extern int Multi_display_netinfo;
3573 if(Multi_display_netinfo){
3574 extern void multi_display_netinfo();
3575 multi_display_netinfo();
3578 game_tst_frame_pre();
3581 do_timing_test(flFrametime);
3585 extern int OO_update_index;
3586 multi_rate_display(OO_update_index, 375, 0);
3591 extern void oo_display();
3598 //#define JOHNS_DEBUG_CODE 1
3600 #ifdef JOHNS_DEBUG_CODE
3601 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3603 //if ( keyd_pressed[KEY_LSHIFT] )
3605 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3607 model_subsystem *turret = tsys->system_info;
3609 if (turret->type == SUBSYSTEM_TURRET ) {
3611 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3613 ship_model_start(tobj);
3615 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3616 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3617 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3619 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3621 ship_model_stop(tobj);
3631 // following function for dumping frames for purposes of building trailers.
3634 // function to toggle state of dumping every frame into PCX when playing the game
3635 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3639 if ( Debug_dump_frames == 0 ) {
3641 Debug_dump_frames = 15;
3642 Debug_dump_trigger = 0;
3643 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3644 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3647 Debug_dump_frames = 0;
3648 Debug_dump_trigger = 0;
3649 gr_dump_frame_stop();
3650 dc_printf( "Frame dumping is now OFF\n" );
3656 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3660 if ( Debug_dump_frames == 0 ) {
3662 Debug_dump_frames = 15;
3663 Debug_dump_trigger = 1;
3664 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3665 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3668 Debug_dump_frames = 0;
3669 Debug_dump_trigger = 0;
3670 gr_dump_frame_stop();
3671 dc_printf( "Frame dumping is now OFF\n" );
3677 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3681 if ( Debug_dump_frames == 0 ) {
3683 Debug_dump_frames = 30;
3684 Debug_dump_trigger = 0;
3685 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3686 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3689 Debug_dump_frames = 0;
3690 Debug_dump_trigger = 0;
3691 gr_dump_frame_stop();
3692 dc_printf( "Frame dumping is now OFF\n" );
3698 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3702 if ( Debug_dump_frames == 0 ) {
3704 Debug_dump_frames = 30;
3705 Debug_dump_trigger = 1;
3706 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3707 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3710 Debug_dump_frames = 0;
3711 Debug_dump_trigger = 0;
3712 gr_dump_frame_stop();
3713 dc_printf( "Triggered frame dumping is now OFF\n" );
3719 void game_maybe_dump_frame()
3721 if ( !Debug_dump_frames ){
3725 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3732 Debug_dump_frame_num++;
3738 extern int Player_dead_state;
3740 // Flip the page and time how long it took.
3741 void game_flip_page_and_time_it()
3745 t1 = timer_get_fixed_seconds();
3747 t2 = timer_get_fixed_seconds();
3749 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3750 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3753 void game_simulation_frame()
3755 // blow ships up in multiplayer dogfight
3756 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){
3757 // blow up all non-player ships
3758 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3761 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3763 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)){
3764 moveup = GET_NEXT(moveup);
3767 shipp = &Ships[Objects[moveup->objnum].instance];
3768 sip = &Ship_info[shipp->ship_info_index];
3770 // only blow up small ships
3771 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3772 // function to simply explode a ship where it is currently at
3773 ship_self_destruct( &Objects[moveup->objnum] );
3776 moveup = GET_NEXT(moveup);
3782 // process AWACS stuff - do this first thing
3785 // single player, set Player hits_this_frame to 0
3786 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3787 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3788 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3792 supernova_process();
3793 if(supernova_active() >= 5){
3797 // fire targeting lasers now so that
3798 // 1 - created this frame
3799 // 2 - collide this frame
3800 // 3 - render this frame
3801 // 4 - ignored and deleted next frame
3802 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3804 ship_process_targeting_lasers();
3806 // do this here so that it works for multiplayer
3808 // get viewer direction
3809 int viewer_direction = PHYSICS_VIEWER_REAR;
3811 if(Viewer_mode == 0){
3812 viewer_direction = PHYSICS_VIEWER_FRONT;
3814 if(Viewer_mode & VM_PADLOCK_UP){
3815 viewer_direction = PHYSICS_VIEWER_UP;
3817 else if(Viewer_mode & VM_PADLOCK_REAR){
3818 viewer_direction = PHYSICS_VIEWER_REAR;
3820 else if(Viewer_mode & VM_PADLOCK_LEFT){
3821 viewer_direction = PHYSICS_VIEWER_LEFT;
3823 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3824 viewer_direction = PHYSICS_VIEWER_RIGHT;
3827 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3829 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3832 #define VM_PADLOCK_UP (1 << 7)
3833 #define VM_PADLOCK_REAR (1 << 8)
3834 #define VM_PADLOCK_LEFT (1 << 9)
3835 #define VM_PADLOCK_RIGHT (1 << 10)
3837 // evaluate mission departures and arrivals before we process all objects.
3838 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3840 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3841 // ships/wing packets.
3842 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3843 mission_parse_eval_stuff();
3846 // if we're an observer, move ourselves seperately from the standard physics
3847 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3848 obj_observer_move(flFrametime);
3851 // move all the objects now
3852 obj_move_all(flFrametime);
3854 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3855 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3856 // ship_check_cargo_all();
3857 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3858 mission_eval_goals();
3862 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3863 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3864 training_check_objectives();
3867 // do all interpolation now
3868 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3869 // client side processing of warping in effect stages
3870 multi_do_client_warp(flFrametime);
3872 // client side movement of an observer
3873 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3874 obj_observer_move(flFrametime);
3877 // move all objects - does interpolation now as well
3878 obj_move_all(flFrametime);
3881 // only process the message queue when the player is "in" the game
3882 if ( !Pre_player_entry ){
3883 message_queue_process(); // process any messages send to the player
3886 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3887 message_maybe_distort(); // maybe distort incoming message if comms damaged
3888 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3889 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3890 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3893 if(!(Game_mode & GM_STANDALONE_SERVER)){
3894 // process some stuff every frame (before frame is rendered)
3895 emp_process_local();
3897 hud_update_frame(); // update hud systems
3899 if (!physics_paused) {
3900 // Move particle system
3901 particle_move_all(flFrametime);
3903 // Move missile trails
3904 trail_move_all(flFrametime);
3906 // process muzzle flashes
3907 mflash_process_all();
3909 // Flash the gun flashes
3910 shipfx_flash_do_frame(flFrametime);
3912 shockwave_move_all(flFrametime); // update all the shockwaves
3915 // subspace missile strikes
3918 obj_snd_do_frame(); // update the object-linked persistant sounds
3919 game_maybe_update_sound_environment();
3920 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3922 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3924 if ( Game_subspace_effect ) {
3925 game_start_subspace_ambient_sound();
3931 // Maybe render and process the dead-popup
3932 void game_maybe_do_dead_popup(float frametime)
3934 if ( popupdead_is_active() ) {
3936 int choice = popupdead_do_frame(frametime);
3938 if ( Game_mode & GM_NORMAL ) {
3942 if(game_do_cd_mission_check(Game_current_mission_filename)){
3943 gameseq_post_event(GS_EVENT_ENTER_GAME);
3945 gameseq_post_event(GS_EVENT_MAIN_MENU);
3950 gameseq_post_event(GS_EVENT_END_GAME);
3955 if(game_do_cd_mission_check(Game_current_mission_filename)){
3956 gameseq_post_event(GS_EVENT_START_GAME);
3958 gameseq_post_event(GS_EVENT_MAIN_MENU);
3962 // this should only happen during a red alert mission
3965 Assert(The_mission.red_alert);
3966 if(!The_mission.red_alert){
3968 if(game_do_cd_mission_check(Game_current_mission_filename)){
3969 gameseq_post_event(GS_EVENT_START_GAME);
3971 gameseq_post_event(GS_EVENT_MAIN_MENU);
3976 // choose the previous mission
3977 mission_campaign_previous_mission();
3979 if(game_do_cd_mission_check(Game_current_mission_filename)){
3980 gameseq_post_event(GS_EVENT_START_GAME);
3982 gameseq_post_event(GS_EVENT_MAIN_MENU);
3993 case POPUPDEAD_DO_MAIN_HALL:
3994 multi_quit_game(PROMPT_NONE,-1);
3997 case POPUPDEAD_DO_RESPAWN:
3998 multi_respawn_normal();
3999 event_music_player_respawn();
4002 case POPUPDEAD_DO_OBSERVER:
4003 multi_respawn_observer();
4004 event_music_player_respawn_as_observer();
4013 if ( leave_popup ) {
4019 // returns true if player is actually in a game_play stats
4020 int game_actually_playing()
4024 state = gameseq_get_state();
4025 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4031 // Draw the 2D HUD gauges
4032 void game_render_hud_2d()
4034 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4038 HUD_render_2d(flFrametime);
4042 // Draw the 3D-dependant HUD gauges
4043 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4045 g3_start_frame(0); // 0 = turn zbuffering off
4046 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4048 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4049 HUD_render_3d(flFrametime);
4053 game_sunspot_process(flFrametime);
4055 // Diminish the palette effect
4056 game_flash_diminish(flFrametime);
4064 int actually_playing;
4065 fix total_time1, total_time2;
4066 fix render2_time1=0, render2_time2=0;
4067 fix render3_time1=0, render3_time2=0;
4068 fix flip_time1=0, flip_time2=0;
4069 fix clear_time1=0, clear_time2=0;
4075 if (Framerate_delay) {
4076 int start_time = timer_get_milliseconds();
4077 while (timer_get_milliseconds() < start_time + Framerate_delay)
4083 demo_do_frame_start();
4085 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4090 // start timing frame
4091 timing_frame_start();
4093 total_time1 = timer_get_fixed_seconds();
4095 // var to hold which state we are in
4096 actually_playing = game_actually_playing();
4098 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4099 if (!(Game_mode & GM_STANDALONE_SERVER)){
4100 Assert( OBJ_INDEX(Player_obj) >= 0 );
4104 if (Missiontime > Entry_delay_time){
4105 Pre_player_entry = 0;
4107 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4110 // Note: These are done even before the player enters, else buffers can overflow.
4111 if (! (Game_mode & GM_STANDALONE_SERVER)){
4115 shield_frame_init();
4117 if ( Player->control_mode != PCM_NORMAL )
4120 if ( !Pre_player_entry && actually_playing ) {
4121 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4123 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4124 game_process_keys();
4126 // don't read flying controls if we're playing a demo back
4127 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4128 read_player_controls( Player_obj, flFrametime);
4132 // if we're not the master, we may have to send the server-critical ship status button_info bits
4133 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4134 multi_maybe_send_ship_status();
4139 // Reset the whack stuff
4142 // These two lines must be outside of Pre_player_entry code,
4143 // otherwise too many lights are added.
4146 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4150 game_simulation_frame();
4152 // if not actually in a game play state, then return. This condition could only be true in
4153 // a multiplayer game.
4154 if ( !actually_playing ) {
4155 Assert( Game_mode & GM_MULTIPLAYER );
4159 if (!Pre_player_entry) {
4160 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4161 clear_time1 = timer_get_fixed_seconds();
4162 // clear the screen to black
4164 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4168 clear_time2 = timer_get_fixed_seconds();
4169 render3_time1 = timer_get_fixed_seconds();
4170 game_render_frame_setup(&eye_pos, &eye_orient);
4171 game_render_frame( &eye_pos, &eye_orient );
4173 // save the eye position and orientation
4174 if ( Game_mode & GM_MULTIPLAYER ) {
4175 Net_player->s_info.eye_pos = eye_pos;
4176 Net_player->s_info.eye_orient = eye_orient;
4179 hud_show_target_model();
4181 // check to see if we should display the death died popup
4182 if(Game_mode & GM_DEAD_BLEW_UP){
4183 if(Game_mode & GM_MULTIPLAYER){
4184 // catch the situation where we're supposed to be warping out on this transition
4185 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4186 gameseq_post_event(GS_EVENT_DEBRIEF);
4187 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4188 Player_died_popup_wait = -1;
4192 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4193 Player_died_popup_wait = -1;
4199 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4200 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4201 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4202 if(!popupdead_is_active()){
4206 Player_multi_died_check = -1;
4210 render3_time2 = timer_get_fixed_seconds();
4211 render2_time1 = timer_get_fixed_seconds();
4214 game_get_framerate();
4215 game_show_framerate();
4217 game_show_time_left();
4219 // Draw the 2D HUD gauges
4220 if(supernova_active() < 3){
4221 game_render_hud_2d();
4224 game_set_view_clip();
4226 // Draw 3D HUD gauges
4227 game_render_hud_3d(&eye_pos, &eye_orient);
4231 render2_time2 = timer_get_fixed_seconds();
4233 // maybe render and process the dead popup
4234 game_maybe_do_dead_popup(flFrametime);
4236 // start timing frame
4237 timing_frame_stop();
4238 // timing_display(30, 10);
4240 // If a regular popup is active, don't flip (popup code flips)
4241 if( !popup_running_state() ){
4242 flip_time1 = timer_get_fixed_seconds();
4243 game_flip_page_and_time_it();
4244 flip_time2 = timer_get_fixed_seconds();
4248 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4251 game_show_standalone_framerate();
4255 game_do_training_checks();
4258 // process lightning (nebula only)
4261 total_time2 = timer_get_fixed_seconds();
4263 // Got some timing numbers
4264 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4265 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4266 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4267 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4268 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4271 demo_do_frame_end();
4273 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4279 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4280 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4281 // died. This resulted in screwed up death sequences.
4283 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4284 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4285 static int timer_paused=0;
4286 static int stop_count,start_count;
4287 static int time_stopped,time_started;
4288 int saved_timestamp_ticker = -1;
4290 void game_reset_time()
4292 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4296 // Last_time = timer_get_fixed_seconds();
4302 void game_stop_time()
4304 if (timer_paused==0) {
4306 time = timer_get_fixed_seconds();
4307 // Save how much time progressed so far in the frame so we can
4308 // use it when we unpause.
4309 Last_delta_time = time - Last_time;
4311 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4312 if (Last_delta_time < 0) {
4313 #if defined(TIMER_TEST) && !defined(NDEBUG)
4314 Int3(); //get Matt!!!!
4316 Last_delta_time = 0;
4318 #if defined(TIMER_TEST) && !defined(NDEBUG)
4319 time_stopped = time;
4322 // Stop the timer_tick stuff...
4323 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4324 saved_timestamp_ticker = timestamp_ticker;
4328 #if defined(TIMER_TEST) && !defined(NDEBUG)
4333 void game_start_time()
4336 Assert(timer_paused >= 0);
4337 if (timer_paused==0) {
4339 time = timer_get_fixed_seconds();
4340 #if defined(TIMER_TEST) && !defined(NDEBUG)
4342 Int3(); //get Matt!!!!
4345 // Take current time, and set it backwards to account for time
4346 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4347 // will be correct when it goes to calculate the frametime next
4349 Last_time = time - Last_delta_time;
4350 #if defined(TIMER_TEST) && !defined(NDEBUG)
4351 time_started = time;
4354 // Restore the timer_tick stuff...
4355 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4356 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4357 timestamp_ticker = saved_timestamp_ticker;
4358 saved_timestamp_ticker = -1;
4361 #if defined(TIMER_TEST) && !defined(NDEBUG)
4367 void game_set_frametime(int state)
4370 float frame_cap_diff;
4372 thistime = timer_get_fixed_seconds();
4374 if ( Last_time == 0 )
4375 Frametime = F1_0 / 30;
4377 Frametime = thistime - Last_time;
4379 // Frametime = F1_0 / 30;
4381 fix debug_frametime = Frametime; // Just used to display frametime.
4383 // If player hasn't entered mission yet, make frame take 1/4 second.
4384 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4387 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4389 fix frame_speed = F1_0 / Debug_dump_frames;
4391 if (Frametime > frame_speed ){
4392 nprintf(("warning","slow frame: %x\n",Frametime));
4395 thistime = timer_get_fixed_seconds();
4396 Frametime = thistime - Last_time;
4397 } while (Frametime < frame_speed );
4399 Frametime = frame_speed;
4403 Assert( Framerate_cap > 0 );
4405 // Cap the framerate so it doesn't get too high.
4409 cap = F1_0/Framerate_cap;
4410 if (Frametime < cap) {
4411 thistime = cap - Frametime;
4412 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4413 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4415 thistime = timer_get_fixed_seconds();
4419 if((Game_mode & GM_STANDALONE_SERVER) &&
4420 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4422 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4423 Sleep((DWORD)(frame_cap_diff*1000));
4425 thistime += fl2f((frame_cap_diff));
4427 Frametime = thistime - Last_time;
4430 // If framerate is too low, cap it.
4431 if (Frametime > MAX_FRAMETIME) {
4433 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4435 // to remove warnings in release build
4436 debug_frametime = fl2f(flFrametime);
4438 Frametime = MAX_FRAMETIME;
4441 Frametime = fixmul(Frametime, Game_time_compression);
4443 Last_time = thistime;
4444 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4446 flFrametime = f2fl(Frametime);
4447 //if(!(Game_mode & GM_PLAYING_DEMO)){
4448 timestamp_inc(flFrametime);
4450 /* if ((Framecount > 0) && (Framecount < 10)) {
4451 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4456 // This is called from game_do_frame(), and from navmap_do_frame()
4457 void game_update_missiontime()
4459 // TODO JAS: Put in if and move this into game_set_frametime,
4460 // fix navmap to call game_stop/start_time
4461 //if ( !timer_paused )
4462 Missiontime += Frametime;
4465 void game_do_frame()
4467 game_set_frametime(GS_STATE_GAME_PLAY);
4468 game_update_missiontime();
4470 if (Game_mode & GM_STANDALONE_SERVER) {
4471 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4474 if ( game_single_step && (last_single_step == game_single_step) ) {
4475 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4476 while( key_checkch() == 0 )
4478 os_set_title( XSTR( "FreeSpace", 171) );
4479 Last_time = timer_get_fixed_seconds();
4482 last_single_step = game_single_step;
4484 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4485 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4489 Keep_mouse_centered = 0;
4490 monitor_update(); // Update monitor variables
4493 void multi_maybe_do_frame()
4495 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4500 int Joymouse_button_status = 0;
4502 // Flush all input devices
4510 Joymouse_button_status = 0;
4512 //mprintf(("Game flush!\n" ));
4515 // function for multiplayer only which calls game_do_state_common() when running the
4517 void game_do_dc_networking()
4519 Assert( Game_mode & GM_MULTIPLAYER );
4521 game_do_state_common( gameseq_get_state() );
4524 // Call this whenever in a loop, or when you need to check for a keystroke.
4525 int game_check_key()
4531 // convert keypad enter to normal enter
4532 if ((k & KEY_MASK) == KEY_PADENTER)
4533 k = (k & ~KEY_MASK) | KEY_ENTER;
4540 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4541 static int Demo_show_trailer_timestamp = 0;
4543 void demo_reset_trailer_timer()
4545 Demo_show_trailer_timestamp = timer_get_milliseconds();
4548 void demo_maybe_show_trailer(int k)
4551 // if key pressed, reset demo trailer timer
4553 demo_reset_trailer_timer();
4557 // if mouse moved, reset demo trailer timer
4560 mouse_get_delta(&dx, &dy);
4561 if ( (dx > 0) || (dy > 0) ) {
4562 demo_reset_trailer_timer();
4566 // if joystick has moved, reset demo trailer timer
4569 joy_get_delta(&dx, &dy);
4570 if ( (dx > 0) || (dy > 0) ) {
4571 demo_reset_trailer_timer();
4575 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4576 // the low-level code. Ugly, I know... but was the simplest and most
4579 // if 30 seconds since last demo trailer time reset, launch movie
4580 if ( os_foreground() ) {
4581 int now = timer_get_milliseconds();
4582 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4583 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4585 movie_play( NOX("fstrailer2.mve") );
4586 demo_reset_trailer_timer();
4594 // same as game_check_key(), except this is used while actually in the game. Since there
4595 // generally are differences between game control keys and general UI keys, makes sense to
4596 // have seperate functions for each case. If you are not checking a game control while in a
4597 // mission, you should probably be using game_check_key() instead.
4602 if (!os_foreground()) {
4607 // If we're in a single player game, pause it.
4608 if (!(Game_mode & GM_MULTIPLAYER)){
4609 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4610 game_process_pause_key();
4618 demo_maybe_show_trailer(k);
4621 // Move the mouse cursor with the joystick.
4622 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4623 // Move the mouse cursor with the joystick
4627 joy_get_pos( &jx, &jy, &jz, &jr );
4629 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4630 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4633 mouse_get_real_pos( &mx, &my );
4634 mouse_set_pos( mx+dx, my+dy );
4639 m = mouse_down(MOUSE_LEFT_BUTTON);
4641 if ( j != Joymouse_button_status ) {
4642 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4643 Joymouse_button_status = j;
4645 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4646 } else if ( (!j) && (m) ) {
4647 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4652 // if we should be ignoring keys because of some multiplayer situations
4653 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4657 // If a popup is running, don't process all the Fn keys
4658 if( popup_active() ) {
4662 state = gameseq_get_state();
4664 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4667 case KEY_DEBUGGED + KEY_BACKSP:
4672 launch_context_help();
4677 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4679 // don't allow f2 while warping out in multiplayer
4680 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4685 case GS_STATE_INITIAL_PLAYER_SELECT:
4686 case GS_STATE_OPTIONS_MENU:
4687 case GS_STATE_HUD_CONFIG:
4688 case GS_STATE_CONTROL_CONFIG:
4689 case GS_STATE_DEATH_DIED:
4690 case GS_STATE_DEATH_BLEW_UP:
4691 case GS_STATE_VIEW_MEDALS:
4695 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4702 // hotkey selection screen -- only valid from briefing and beyond.
4705 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) ) {
4706 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4712 case KEY_DEBUGGED + KEY_F3:
4713 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4716 case KEY_DEBUGGED + KEY_F4:
4717 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4721 if(Game_mode & GM_MULTIPLAYER){
4722 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4723 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4727 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4728 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4734 case KEY_ESC | KEY_SHIFTED:
4735 // make sure to quit properly out of multiplayer
4736 if(Game_mode & GM_MULTIPLAYER){
4737 multi_quit_game(PROMPT_NONE);
4740 gameseq_post_event( GS_EVENT_QUIT_GAME );
4745 case KEY_DEBUGGED + KEY_P:
4748 case KEY_PRINT_SCRN:
4750 static int counter = 0;
4755 sprintf( tmp_name, NOX("screen%02d"), counter );
4757 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4758 gr_print_screen(tmp_name);
4766 case KEY_SHIFTED | KEY_ENTER: {
4768 #if !defined(NDEBUG)
4770 if ( Game_mode & GM_NORMAL ){
4774 // if we're in multiplayer mode, do some special networking
4775 if(Game_mode & GM_MULTIPLAYER){
4776 debug_console(game_do_dc_networking);
4783 if ( Game_mode & GM_NORMAL )
4797 gameseq_post_event(GS_EVENT_QUIT_GAME);
4800 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4803 void camera_set_position( vector *pos )
4808 void camera_set_orient( matrix *orient )
4810 Camera_orient = *orient;
4813 void camera_set_velocity( vector *vel, int instantaneous )
4815 Camera_desired_velocity.x = 0.0f;
4816 Camera_desired_velocity.y = 0.0f;
4817 Camera_desired_velocity.z = 0.0f;
4819 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4820 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4821 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4823 if ( instantaneous ) {
4824 Camera_velocity = Camera_desired_velocity;
4832 vector new_vel, delta_pos;
4834 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4835 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4836 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4838 Camera_velocity = new_vel;
4840 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4842 vm_vec_add2( &Camera_pos, &delta_pos );
4844 float ot = Camera_time+0.0f;
4846 Camera_time += flFrametime;
4848 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4851 tmp.z = 4.739f; // always go this fast forward.
4853 // pick x and y velocities so they are always on a
4854 // circle with a 25 m radius.
4856 float tmp_angle = frand()*PI2;
4858 tmp.x = 22.0f * (float)sin(tmp_angle);
4859 tmp.y = -22.0f * (float)cos(tmp_angle);
4861 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4863 //mprintf(( "Changing velocity!\n" ));
4864 camera_set_velocity( &tmp, 0 );
4867 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4868 vector tmp = { 0.0f, 0.0f, 0.0f };
4869 camera_set_velocity( &tmp, 0 );
4874 void end_demo_campaign_do()
4876 #if defined(FS2_DEMO)
4877 // show upsell screens
4878 demo_upsell_show_screens();
4879 #elif defined(OEM_BUILD)
4880 // show oem upsell screens
4881 oem_upsell_show_screens();
4884 // drop into main hall
4885 gameseq_post_event( GS_EVENT_MAIN_MENU );
4888 // All code to process events. This is the only place
4889 // that you should change the state of the game.
4890 void game_process_event( int current_state, int event )
4892 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4895 case GS_EVENT_SIMULATOR_ROOM:
4896 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4899 case GS_EVENT_MAIN_MENU:
4900 gameseq_set_state(GS_STATE_MAIN_MENU);
4903 case GS_EVENT_OPTIONS_MENU:
4904 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4907 case GS_EVENT_BARRACKS_MENU:
4908 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4911 case GS_EVENT_TECH_MENU:
4912 gameseq_set_state(GS_STATE_TECH_MENU);
4915 case GS_EVENT_TRAINING_MENU:
4916 gameseq_set_state(GS_STATE_TRAINING_MENU);
4919 case GS_EVENT_START_GAME:
4920 Select_default_ship = 0;
4921 Player_multi_died_check = -1;
4922 gameseq_set_state(GS_STATE_CMD_BRIEF);
4925 case GS_EVENT_START_BRIEFING:
4926 gameseq_set_state(GS_STATE_BRIEFING);
4929 case GS_EVENT_DEBRIEF:
4930 // did we end the campaign in the main freespace 2 single player campaign?
4931 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4932 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4934 gameseq_set_state(GS_STATE_DEBRIEF);
4937 Player_multi_died_check = -1;
4940 case GS_EVENT_SHIP_SELECTION:
4941 gameseq_set_state( GS_STATE_SHIP_SELECT );
4944 case GS_EVENT_WEAPON_SELECTION:
4945 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4948 case GS_EVENT_ENTER_GAME:
4950 // maybe start recording a demo
4952 demo_start_record("test.fsd");
4956 if (Game_mode & GM_MULTIPLAYER) {
4957 // if we're respawning, make sure we change the view mode so that the hud shows up
4958 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4962 gameseq_set_state(GS_STATE_GAME_PLAY);
4964 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4967 Player_multi_died_check = -1;
4969 // clear multiplayer button info
4970 extern button_info Multi_ship_status_bi;
4971 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4973 Start_time = f2fl(timer_get_approx_seconds());
4975 mprintf(("Entering game at time = %7.3f\n", Start_time));
4979 case GS_EVENT_START_GAME_QUICK:
4980 Select_default_ship = 1;
4981 gameseq_post_event(GS_EVENT_ENTER_GAME);
4985 case GS_EVENT_END_GAME:
4986 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4987 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4988 gameseq_set_state(GS_STATE_MAIN_MENU);
4993 Player_multi_died_check = -1;
4996 case GS_EVENT_QUIT_GAME:
4997 main_hall_stop_music();
4998 main_hall_stop_ambient();
4999 gameseq_set_state(GS_STATE_QUIT_GAME);
5001 Player_multi_died_check = -1;
5004 case GS_EVENT_GAMEPLAY_HELP:
5005 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5008 case GS_EVENT_PAUSE_GAME:
5009 gameseq_push_state(GS_STATE_GAME_PAUSED);
5012 case GS_EVENT_DEBUG_PAUSE_GAME:
5013 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5016 case GS_EVENT_TRAINING_PAUSE:
5017 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5020 case GS_EVENT_PREVIOUS_STATE:
5021 gameseq_pop_state();
5024 case GS_EVENT_TOGGLE_FULLSCREEN:
5025 #ifndef HARDWARE_ONLY
5027 if ( gr_screen.mode == GR_SOFTWARE ) {
5028 gr_init( GR_640, GR_DIRECTDRAW );
5029 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5030 gr_init( GR_640, GR_SOFTWARE );
5036 case GS_EVENT_TOGGLE_GLIDE:
5038 if ( gr_screen.mode != GR_GLIDE ) {
5039 gr_init( GR_640, GR_GLIDE );
5041 gr_init( GR_640, GR_SOFTWARE );
5046 case GS_EVENT_LOAD_MISSION_MENU:
5047 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5050 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5051 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5054 case GS_EVENT_HUD_CONFIG:
5055 gameseq_push_state( GS_STATE_HUD_CONFIG );
5058 case GS_EVENT_CONTROL_CONFIG:
5059 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5062 case GS_EVENT_DEATH_DIED:
5063 gameseq_set_state( GS_STATE_DEATH_DIED );
5066 case GS_EVENT_DEATH_BLEW_UP:
5067 if ( current_state == GS_STATE_DEATH_DIED ) {
5068 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5069 event_music_player_death();
5071 // multiplayer clients set their extra check here
5072 if(Game_mode & GM_MULTIPLAYER){
5073 // set the multi died absolute last chance check
5074 Player_multi_died_check = time(NULL);
5077 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5081 case GS_EVENT_NEW_CAMPAIGN:
5082 if (!mission_load_up_campaign()){
5083 readyroom_continue_campaign();
5086 Player_multi_died_check = -1;
5089 case GS_EVENT_CAMPAIGN_CHEAT:
5090 if (!mission_load_up_campaign()){
5092 // bash campaign value
5093 extern char Main_hall_campaign_cheat[512];
5096 // look for the mission
5097 for(idx=0; idx<Campaign.num_missions; idx++){
5098 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5099 Campaign.next_mission = idx;
5100 Campaign.prev_mission = idx - 1;
5107 readyroom_continue_campaign();
5110 Player_multi_died_check = -1;
5113 case GS_EVENT_CAMPAIGN_ROOM:
5114 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5117 case GS_EVENT_CMD_BRIEF:
5118 gameseq_set_state(GS_STATE_CMD_BRIEF);
5121 case GS_EVENT_RED_ALERT:
5122 gameseq_set_state(GS_STATE_RED_ALERT);
5125 case GS_EVENT_CREDITS:
5126 gameseq_set_state( GS_STATE_CREDITS );
5129 case GS_EVENT_VIEW_MEDALS:
5130 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5133 case GS_EVENT_SHOW_GOALS:
5134 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5137 case GS_EVENT_HOTKEY_SCREEN:
5138 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5141 // multiplayer stuff follow these comments
5143 case GS_EVENT_MULTI_JOIN_GAME:
5144 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5147 case GS_EVENT_MULTI_HOST_SETUP:
5148 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5151 case GS_EVENT_MULTI_CLIENT_SETUP:
5152 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5155 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5156 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5159 case GS_EVENT_MULTI_STD_WAIT:
5160 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5163 case GS_EVENT_STANDALONE_MAIN:
5164 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5167 case GS_EVENT_MULTI_PAUSE:
5168 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5171 case GS_EVENT_INGAME_PRE_JOIN:
5172 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5175 case GS_EVENT_EVENT_DEBUG:
5176 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5179 // Start a warpout where player automatically goes 70 no matter what
5180 // and can't cancel out of it.
5181 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5182 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5184 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5185 Player->saved_viewer_mode = Viewer_mode;
5186 Player->control_mode = PCM_WARPOUT_STAGE1;
5187 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5188 Warpout_time = 0.0f; // Start timer!
5191 case GS_EVENT_PLAYER_WARPOUT_START:
5192 if ( Player->control_mode != PCM_NORMAL ) {
5193 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5195 Player->saved_viewer_mode = Viewer_mode;
5196 Player->control_mode = PCM_WARPOUT_STAGE1;
5197 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5198 Warpout_time = 0.0f; // Start timer!
5199 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5203 case GS_EVENT_PLAYER_WARPOUT_STOP:
5204 if ( Player->control_mode != PCM_NORMAL ) {
5205 if ( !Warpout_forced ) { // cannot cancel forced warpout
5206 Player->control_mode = PCM_NORMAL;
5207 Viewer_mode = Player->saved_viewer_mode;
5208 hud_subspace_notify_abort();
5209 mprintf(( "Player put back to normal mode.\n" ));
5210 if ( Warpout_sound > -1 ) {
5211 snd_stop( Warpout_sound );
5218 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5219 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5220 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5221 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5223 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5224 shipfx_warpout_start( Player_obj );
5225 Player->control_mode = PCM_WARPOUT_STAGE2;
5226 Player->saved_viewer_mode = Viewer_mode;
5227 Viewer_mode |= VM_WARP_CHASE;
5229 vector tmp = Player_obj->pos;
5231 ship_get_eye( &tmp, &tmp_m, Player_obj );
5232 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5233 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5234 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5236 camera_set_position( &tmp );
5237 camera_set_orient( &Player_obj->orient );
5238 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5240 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5241 camera_set_velocity( &tmp_vel, 1);
5245 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5246 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5247 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5248 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5250 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5251 Player->control_mode = PCM_WARPOUT_STAGE3;
5255 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5256 mprintf(( "Player warped out. Going to debriefing!\n" ));
5257 Player->control_mode = PCM_NORMAL;
5258 Viewer_mode = Player->saved_viewer_mode;
5261 // we have a special debriefing screen for multiplayer furballs
5262 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5263 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5265 // do the normal debriefing for all other situations
5267 gameseq_post_event(GS_EVENT_DEBRIEF);
5271 case GS_EVENT_STANDALONE_POSTGAME:
5272 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5275 case GS_EVENT_INITIAL_PLAYER_SELECT:
5276 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5279 case GS_EVENT_GAME_INIT:
5280 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5281 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5283 // see if the command line option has been set to use the last pilot, and act acoordingly
5284 if( player_select_get_last_pilot() ) {
5285 // always enter the main menu -- do the automatic network startup stuff elsewhere
5286 // so that we still have valid checks for networking modes, etc.
5287 gameseq_set_state(GS_STATE_MAIN_MENU);
5289 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5294 case GS_EVENT_MULTI_MISSION_SYNC:
5295 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5298 case GS_EVENT_MULTI_START_GAME:
5299 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5302 case GS_EVENT_MULTI_HOST_OPTIONS:
5303 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5306 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5307 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5310 case GS_EVENT_TEAM_SELECT:
5311 gameseq_set_state(GS_STATE_TEAM_SELECT);
5314 case GS_EVENT_END_CAMPAIGN:
5315 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5318 case GS_EVENT_END_DEMO:
5319 gameseq_set_state(GS_STATE_END_DEMO);
5322 case GS_EVENT_LOOP_BRIEF:
5323 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5332 // Called when a state is being left.
5333 // The current state is still at old_state, but as soon as
5334 // this function leaves, then the current state will become
5335 // new state. You should never try to change the state
5336 // in here... if you think you need to, you probably really
5337 // need to post an event, not change the state.
5338 void game_leave_state( int old_state, int new_state )
5340 int end_mission = 1;
5342 switch (new_state) {
5343 case GS_STATE_GAME_PAUSED:
5344 case GS_STATE_DEBUG_PAUSED:
5345 case GS_STATE_OPTIONS_MENU:
5346 case GS_STATE_CONTROL_CONFIG:
5347 case GS_STATE_MISSION_LOG_SCROLLBACK:
5348 case GS_STATE_DEATH_DIED:
5349 case GS_STATE_SHOW_GOALS:
5350 case GS_STATE_HOTKEY_SCREEN:
5351 case GS_STATE_MULTI_PAUSED:
5352 case GS_STATE_TRAINING_PAUSED:
5353 case GS_STATE_EVENT_DEBUG:
5354 case GS_STATE_GAMEPLAY_HELP:
5355 end_mission = 0; // these events shouldn't end a mission
5359 switch (old_state) {
5360 case GS_STATE_BRIEFING:
5361 brief_stop_voices();
5362 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5363 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5364 && (new_state != GS_STATE_TEAM_SELECT) ){
5365 common_select_close();
5366 if ( new_state == GS_STATE_MAIN_MENU ) {
5367 freespace_stop_mission();
5371 // COMMAND LINE OPTION
5372 if (Cmdline_multi_stream_chat_to_file){
5373 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5374 cfclose(Multi_chat_stream);
5378 case GS_STATE_DEBRIEF:
5379 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5384 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5385 multi_df_debrief_close();
5388 case GS_STATE_LOAD_MISSION_MENU:
5389 mission_load_menu_close();
5392 case GS_STATE_SIMULATOR_ROOM:
5396 case GS_STATE_CAMPAIGN_ROOM:
5397 campaign_room_close();
5400 case GS_STATE_CMD_BRIEF:
5401 if (new_state == GS_STATE_OPTIONS_MENU) {
5406 if (new_state == GS_STATE_MAIN_MENU)
5407 freespace_stop_mission();
5412 case GS_STATE_RED_ALERT:
5416 case GS_STATE_SHIP_SELECT:
5417 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5418 new_state != GS_STATE_HOTKEY_SCREEN &&
5419 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5420 common_select_close();
5421 if ( new_state == GS_STATE_MAIN_MENU ) {
5422 freespace_stop_mission();
5427 case GS_STATE_WEAPON_SELECT:
5428 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5429 new_state != GS_STATE_HOTKEY_SCREEN &&
5430 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5431 common_select_close();
5432 if ( new_state == GS_STATE_MAIN_MENU ) {
5433 freespace_stop_mission();
5438 case GS_STATE_TEAM_SELECT:
5439 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5440 new_state != GS_STATE_HOTKEY_SCREEN &&
5441 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5442 common_select_close();
5443 if ( new_state == GS_STATE_MAIN_MENU ) {
5444 freespace_stop_mission();
5449 case GS_STATE_MAIN_MENU:
5450 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5457 case GS_STATE_OPTIONS_MENU:
5458 //game_start_time();
5459 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5460 multi_join_clear_game_list();
5462 options_menu_close();
5465 case GS_STATE_BARRACKS_MENU:
5466 if(new_state != GS_STATE_VIEW_MEDALS){
5471 case GS_STATE_MISSION_LOG_SCROLLBACK:
5472 hud_scrollback_close();
5475 case GS_STATE_TRAINING_MENU:
5476 training_menu_close();
5479 case GS_STATE_GAME_PLAY:
5480 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5481 player_save_target_and_weapon_link_prefs();
5482 game_stop_looped_sounds();
5485 sound_env_disable();
5486 joy_ff_stop_effects();
5488 // stop game time under certain conditions
5489 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5494 // shut down any recording or playing demos
5499 // when in multiplayer and going back to the main menu, send a leave game packet
5500 // right away (before calling stop mission). stop_mission was taking to long to
5501 // close mission down and I want people to get notified ASAP.
5502 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5503 multi_quit_game(PROMPT_NONE);
5506 freespace_stop_mission();
5507 Game_time_compression = F1_0;
5511 case GS_STATE_TECH_MENU:
5515 case GS_STATE_TRAINING_PAUSED:
5516 Training_num_lines = 0;
5517 // fall through to GS_STATE_GAME_PAUSED
5519 case GS_STATE_GAME_PAUSED:
5521 if ( end_mission ) {
5526 case GS_STATE_DEBUG_PAUSED:
5529 pause_debug_close();
5533 case GS_STATE_HUD_CONFIG:
5537 // join/start a game
5538 case GS_STATE_MULTI_JOIN_GAME:
5539 if(new_state != GS_STATE_OPTIONS_MENU){
5540 multi_join_game_close();
5544 case GS_STATE_MULTI_HOST_SETUP:
5545 case GS_STATE_MULTI_CLIENT_SETUP:
5546 // if this is just the host going into the options screen, don't do anything
5547 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5551 // close down the proper state
5552 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5553 multi_create_game_close();
5555 multi_game_client_setup_close();
5558 // COMMAND LINE OPTION
5559 if (Cmdline_multi_stream_chat_to_file){
5560 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5561 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5562 cfclose(Multi_chat_stream);
5567 case GS_STATE_CONTROL_CONFIG:
5568 control_config_close();
5571 case GS_STATE_DEATH_DIED:
5572 Game_mode &= ~GM_DEAD_DIED;
5574 // early end while respawning or blowing up in a multiplayer game
5575 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5577 freespace_stop_mission();
5581 case GS_STATE_DEATH_BLEW_UP:
5582 Game_mode &= ~GM_DEAD_BLEW_UP;
5584 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5585 // to determine if I should do anything.
5586 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5588 freespace_stop_mission();
5591 // if we are not respawing as an observer or as a player, our new state will not
5592 // be gameplay state.
5593 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5594 game_stop_time(); // hasn't been called yet!!
5595 freespace_stop_mission();
5601 case GS_STATE_CREDITS:
5605 case GS_STATE_VIEW_MEDALS:
5609 case GS_STATE_SHOW_GOALS:
5610 mission_show_goals_close();
5613 case GS_STATE_HOTKEY_SCREEN:
5614 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5615 mission_hotkey_close();
5619 case GS_STATE_MULTI_MISSION_SYNC:
5620 // if we're moving into the options menu, don't do anything
5621 if(new_state == GS_STATE_OPTIONS_MENU){
5625 Assert( Game_mode & GM_MULTIPLAYER );
5627 if ( new_state == GS_STATE_GAME_PLAY ){
5628 // palette_restore_palette();
5630 // change a couple of flags to indicate our state!!!
5631 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5632 send_netplayer_update_packet();
5634 // set the game mode
5635 Game_mode |= GM_IN_MISSION;
5639 case GS_STATE_VIEW_CUTSCENES:
5640 cutscenes_screen_close();
5643 case GS_STATE_MULTI_STD_WAIT:
5644 multi_standalone_wait_close();
5647 case GS_STATE_STANDALONE_MAIN:
5648 standalone_main_close();
5649 if(new_state == GS_STATE_MULTI_STD_WAIT){
5650 init_multiplayer_stats();
5654 case GS_STATE_MULTI_PAUSED:
5655 // if ( end_mission ){
5660 case GS_STATE_INGAME_PRE_JOIN:
5661 multi_ingame_select_close();
5664 case GS_STATE_STANDALONE_POSTGAME:
5665 multi_standalone_postgame_close();
5668 case GS_STATE_INITIAL_PLAYER_SELECT:
5669 player_select_close();
5672 case GS_STATE_MULTI_START_GAME:
5673 multi_start_game_close();
5676 case GS_STATE_MULTI_HOST_OPTIONS:
5677 multi_host_options_close();
5680 case GS_STATE_END_OF_CAMPAIGN:
5681 mission_campaign_end_close();
5684 case GS_STATE_LOOP_BRIEF:
5690 // Called when a state is being entered.
5691 // The current state is set to the state we're entering at
5692 // this point, and old_state is set to the state we're coming
5693 // from. You should never try to change the state
5694 // in here... if you think you need to, you probably really
5695 // need to post an event, not change the state.
5697 void game_enter_state( int old_state, int new_state )
5699 switch (new_state) {
5700 case GS_STATE_MAIN_MENU:
5701 // in multiplayer mode, be sure that we are not doing networking anymore.
5702 if ( Game_mode & GM_MULTIPLAYER ) {
5703 Assert( Net_player != NULL );
5704 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5707 Game_time_compression = F1_0;
5709 // determine which ship this guy is currently based on
5710 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5713 if (Player->on_bastion) {
5721 case GS_STATE_BRIEFING:
5722 main_hall_stop_music();
5723 main_hall_stop_ambient();
5725 if (Game_mode & GM_NORMAL) {
5726 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5727 // MWA: or from options or hotkey screens
5728 // JH: or if the command brief state already did this
5729 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5730 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5731 && (old_state != GS_STATE_CMD_BRIEF) ) {
5732 if ( !game_start_mission() ) // this should put us into a new state on failure!
5736 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5737 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5738 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5740 Game_time_compression = F1_0;
5742 if ( red_alert_mission() ) {
5743 gameseq_post_event(GS_EVENT_RED_ALERT);
5750 case GS_STATE_DEBRIEF:
5751 game_stop_looped_sounds();
5752 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5753 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5758 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5759 multi_df_debrief_init();
5762 case GS_STATE_LOAD_MISSION_MENU:
5763 mission_load_menu_init();
5766 case GS_STATE_SIMULATOR_ROOM:
5770 case GS_STATE_CAMPAIGN_ROOM:
5771 campaign_room_init();
5774 case GS_STATE_RED_ALERT:
5775 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5779 case GS_STATE_CMD_BRIEF: {
5780 int team_num = 0; // team number used as index for which cmd brief to use.
5782 if (old_state == GS_STATE_OPTIONS_MENU) {
5786 main_hall_stop_music();
5787 main_hall_stop_ambient();
5789 if (Game_mode & GM_NORMAL) {
5790 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5791 // MWA: or from options or hotkey screens
5792 // JH: or if the command brief state already did this
5793 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5794 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5795 if ( !game_start_mission() ) // this should put us into a new state on failure!
5800 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5801 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5802 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5804 cmd_brief_init(team_num);
5810 case GS_STATE_SHIP_SELECT:
5814 case GS_STATE_WEAPON_SELECT:
5815 weapon_select_init();
5818 case GS_STATE_TEAM_SELECT:
5822 case GS_STATE_GAME_PAUSED:
5827 case GS_STATE_DEBUG_PAUSED:
5828 // game_stop_time();
5829 // os_set_title("FreeSpace - PAUSED");
5832 case GS_STATE_TRAINING_PAUSED:
5839 case GS_STATE_OPTIONS_MENU:
5841 options_menu_init();
5844 case GS_STATE_GAME_PLAY:
5845 // coming from the gameplay state or the main menu, we might need to load the mission
5846 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5847 if ( !game_start_mission() ) // this should put us into a new state.
5852 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5853 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5854 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5855 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5856 (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) ) {
5857 // JAS: Used to do all paging here.
5861 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5865 main_hall_stop_music();
5866 main_hall_stop_ambient();
5867 event_music_first_pattern(); // start the first pattern
5870 // special code that restores player ship selection and weapons loadout when doing a quick start
5871 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5872 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5873 wss_direct_restore_loadout();
5877 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5878 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5879 event_music_first_pattern(); // start the first pattern
5882 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5883 event_music_first_pattern(); // start the first pattern
5885 player_restore_target_and_weapon_link_prefs();
5887 Game_mode |= GM_IN_MISSION;
5890 // required to truely make mouse deltas zeroed in debug mouse code
5891 void mouse_force_pos(int x, int y);
5892 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5897 // only start time if in single player, or coming from multi wait state
5900 (Game_mode & GM_NORMAL) &&
5901 (old_state != GS_STATE_VIEW_CUTSCENES)
5903 (Game_mode & GM_MULTIPLAYER) && (
5904 (old_state == GS_STATE_MULTI_PAUSED) ||
5905 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5911 // when coming from the multi paused state, reset the timestamps
5912 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5913 multi_reset_timestamps();
5916 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5917 // initialize all object update details
5918 multi_oo_gameplay_init();
5921 // under certain circumstances, the server should reset the object update rate limiting stuff
5922 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5923 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5925 // reinitialize the rate limiting system for all clients
5926 multi_oo_rate_init_all();
5929 // multiplayer clients should always re-initialize their control info rate limiting system
5930 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5931 multi_oo_rate_init_all();
5935 if(Game_mode & GM_MULTIPLAYER){
5936 multi_ping_reset_players();
5939 Game_subspace_effect = 0;
5940 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5941 Game_subspace_effect = 1;
5942 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5943 game_start_subspace_ambient_sound();
5947 sound_env_set(&Game_sound_env);
5948 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5950 // clear multiplayer button info i
5951 extern button_info Multi_ship_status_bi;
5952 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5955 case GS_STATE_HUD_CONFIG:
5959 case GS_STATE_MULTI_JOIN_GAME:
5960 multi_join_clear_game_list();
5962 if (old_state != GS_STATE_OPTIONS_MENU) {
5963 multi_join_game_init();
5968 case GS_STATE_MULTI_HOST_SETUP:
5969 // don't reinitialize if we're coming back from the host options screen
5970 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5971 multi_create_game_init();
5976 case GS_STATE_MULTI_CLIENT_SETUP:
5977 if (old_state != GS_STATE_OPTIONS_MENU) {
5978 multi_game_client_setup_init();
5983 case GS_STATE_CONTROL_CONFIG:
5984 control_config_init();
5987 case GS_STATE_TECH_MENU:
5991 case GS_STATE_BARRACKS_MENU:
5992 if(old_state != GS_STATE_VIEW_MEDALS){
5997 case GS_STATE_MISSION_LOG_SCROLLBACK:
5998 hud_scrollback_init();
6001 case GS_STATE_DEATH_DIED:
6002 Player_died_time = timestamp(10);
6004 if(!(Game_mode & GM_MULTIPLAYER)){
6005 player_show_death_message();
6007 Game_mode |= GM_DEAD_DIED;
6010 case GS_STATE_DEATH_BLEW_UP:
6011 if ( !popupdead_is_active() ) {
6012 Player_ai->target_objnum = -1;
6015 // stop any local EMP effect
6018 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6019 Game_mode |= GM_DEAD_BLEW_UP;
6020 Show_viewing_from_self = 0;
6022 // timestamp how long we should wait before displaying the died popup
6023 if ( !popupdead_is_active() ) {
6024 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6028 case GS_STATE_GAMEPLAY_HELP:
6029 gameplay_help_init();
6032 case GS_STATE_CREDITS:
6033 main_hall_stop_music();
6034 main_hall_stop_ambient();
6038 case GS_STATE_VIEW_MEDALS:
6039 medal_main_init(Player);
6042 case GS_STATE_SHOW_GOALS:
6043 mission_show_goals_init();
6046 case GS_STATE_HOTKEY_SCREEN:
6047 mission_hotkey_init();
6050 case GS_STATE_MULTI_MISSION_SYNC:
6051 // if we're coming from the options screen, don't do any
6052 if(old_state == GS_STATE_OPTIONS_MENU){
6056 switch(Multi_sync_mode){
6057 case MULTI_SYNC_PRE_BRIEFING:
6058 // if moving from game forming to the team select state
6061 case MULTI_SYNC_POST_BRIEFING:
6062 // if moving from briefing into the mission itself
6065 // tell everyone that we're now loading data
6066 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6067 send_netplayer_update_packet();
6069 // JAS: Used to do all paging here!!!!
6071 Net_player->state = NETPLAYER_STATE_WAITING;
6072 send_netplayer_update_packet();
6074 Game_time_compression = F1_0;
6076 case MULTI_SYNC_INGAME:
6082 case GS_STATE_VIEW_CUTSCENES:
6083 cutscenes_screen_init();
6086 case GS_STATE_MULTI_STD_WAIT:
6087 multi_standalone_wait_init();
6090 case GS_STATE_STANDALONE_MAIN:
6091 // don't initialize if we're coming from one of these 2 states unless there are no
6092 // players left (reset situation)
6093 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6094 standalone_main_init();
6098 case GS_STATE_MULTI_PAUSED:
6102 case GS_STATE_INGAME_PRE_JOIN:
6103 multi_ingame_select_init();
6106 case GS_STATE_STANDALONE_POSTGAME:
6107 multi_standalone_postgame_init();
6110 case GS_STATE_INITIAL_PLAYER_SELECT:
6111 player_select_init();
6114 case GS_STATE_MULTI_START_GAME:
6115 multi_start_game_init();
6118 case GS_STATE_MULTI_HOST_OPTIONS:
6119 multi_host_options_init();
6122 case GS_STATE_END_OF_CAMPAIGN:
6123 mission_campaign_end_init();
6126 case GS_STATE_LOOP_BRIEF:
6133 // do stuff that may need to be done regardless of state
6134 void game_do_state_common(int state,int no_networking)
6136 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6137 snd_do_frame(); // update sound system
6138 event_music_do_frame(); // music needs to play across many states
6140 multi_log_process();
6142 if (no_networking) {
6146 // maybe do a multiplayer frame based on game mode and state type
6147 if (Game_mode & GM_MULTIPLAYER) {
6149 case GS_STATE_OPTIONS_MENU:
6150 case GS_STATE_GAMEPLAY_HELP:
6151 case GS_STATE_HOTKEY_SCREEN:
6152 case GS_STATE_HUD_CONFIG:
6153 case GS_STATE_CONTROL_CONFIG:
6154 case GS_STATE_MISSION_LOG_SCROLLBACK:
6155 case GS_STATE_SHOW_GOALS:
6156 case GS_STATE_VIEW_CUTSCENES:
6157 case GS_STATE_EVENT_DEBUG:
6158 multi_maybe_do_frame();
6162 game_do_networking();
6166 // Called once a frame.
6167 // You should never try to change the state
6168 // in here... if you think you need to, you probably really
6169 // need to post an event, not change the state.
6170 int Game_do_state_should_skip = 0;
6171 void game_do_state(int state)
6173 // always lets the do_state_common() function determine if the state should be skipped
6174 Game_do_state_should_skip = 0;
6176 // legal to set the should skip state anywhere in this function
6177 game_do_state_common(state); // do stuff that may need to be done regardless of state
6179 if(Game_do_state_should_skip){
6184 case GS_STATE_MAIN_MENU:
6185 game_set_frametime(GS_STATE_MAIN_MENU);
6186 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6189 main_hall_do(flFrametime);
6193 case GS_STATE_OPTIONS_MENU:
6194 game_set_frametime(GS_STATE_OPTIONS_MENU);
6195 options_menu_do_frame(flFrametime);
6198 case GS_STATE_BARRACKS_MENU:
6199 game_set_frametime(GS_STATE_BARRACKS_MENU);
6200 barracks_do_frame(flFrametime);
6203 case GS_STATE_TRAINING_MENU:
6204 game_set_frametime(GS_STATE_TRAINING_MENU);
6205 training_menu_do_frame(flFrametime);
6208 case GS_STATE_TECH_MENU:
6209 game_set_frametime(GS_STATE_TECH_MENU);
6210 techroom_do_frame(flFrametime);
6213 case GS_STATE_GAMEPLAY_HELP:
6214 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6215 gameplay_help_do_frame(flFrametime);
6218 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6222 case GS_STATE_GAME_PAUSED:
6226 case GS_STATE_DEBUG_PAUSED:
6228 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6233 case GS_STATE_TRAINING_PAUSED:
6234 game_training_pause_do();
6237 case GS_STATE_LOAD_MISSION_MENU:
6238 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6239 mission_load_menu_do();
6242 case GS_STATE_BRIEFING:
6243 game_set_frametime(GS_STATE_BRIEFING);
6244 brief_do_frame(flFrametime);
6247 case GS_STATE_DEBRIEF:
6248 game_set_frametime(GS_STATE_DEBRIEF);
6249 debrief_do_frame(flFrametime);
6252 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6253 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6254 multi_df_debrief_do();
6257 case GS_STATE_SHIP_SELECT:
6258 game_set_frametime(GS_STATE_SHIP_SELECT);
6259 ship_select_do(flFrametime);
6262 case GS_STATE_WEAPON_SELECT:
6263 game_set_frametime(GS_STATE_WEAPON_SELECT);
6264 weapon_select_do(flFrametime);
6267 case GS_STATE_MISSION_LOG_SCROLLBACK:
6268 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6269 hud_scrollback_do_frame(flFrametime);
6272 case GS_STATE_HUD_CONFIG:
6273 game_set_frametime(GS_STATE_HUD_CONFIG);
6274 hud_config_do_frame(flFrametime);
6277 case GS_STATE_MULTI_JOIN_GAME:
6278 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6279 multi_join_game_do_frame();
6282 case GS_STATE_MULTI_HOST_SETUP:
6283 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6284 multi_create_game_do();
6287 case GS_STATE_MULTI_CLIENT_SETUP:
6288 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6289 multi_game_client_setup_do_frame();
6292 case GS_STATE_CONTROL_CONFIG:
6293 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6294 control_config_do_frame(flFrametime);
6297 case GS_STATE_DEATH_DIED:
6301 case GS_STATE_DEATH_BLEW_UP:
6305 case GS_STATE_SIMULATOR_ROOM:
6306 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6307 sim_room_do_frame(flFrametime);
6310 case GS_STATE_CAMPAIGN_ROOM:
6311 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6312 campaign_room_do_frame(flFrametime);
6315 case GS_STATE_RED_ALERT:
6316 game_set_frametime(GS_STATE_RED_ALERT);
6317 red_alert_do_frame(flFrametime);
6320 case GS_STATE_CMD_BRIEF:
6321 game_set_frametime(GS_STATE_CMD_BRIEF);
6322 cmd_brief_do_frame(flFrametime);
6325 case GS_STATE_CREDITS:
6326 game_set_frametime(GS_STATE_CREDITS);
6327 credits_do_frame(flFrametime);
6330 case GS_STATE_VIEW_MEDALS:
6331 game_set_frametime(GS_STATE_VIEW_MEDALS);
6335 case GS_STATE_SHOW_GOALS:
6336 game_set_frametime(GS_STATE_SHOW_GOALS);
6337 mission_show_goals_do_frame(flFrametime);
6340 case GS_STATE_HOTKEY_SCREEN:
6341 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6342 mission_hotkey_do_frame(flFrametime);
6345 case GS_STATE_VIEW_CUTSCENES:
6346 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6347 cutscenes_screen_do_frame();
6350 case GS_STATE_MULTI_STD_WAIT:
6351 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6352 multi_standalone_wait_do();
6355 case GS_STATE_STANDALONE_MAIN:
6356 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6357 standalone_main_do();
6360 case GS_STATE_MULTI_PAUSED:
6361 game_set_frametime(GS_STATE_MULTI_PAUSED);
6365 case GS_STATE_TEAM_SELECT:
6366 game_set_frametime(GS_STATE_TEAM_SELECT);
6370 case GS_STATE_INGAME_PRE_JOIN:
6371 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6372 multi_ingame_select_do();
6375 case GS_STATE_EVENT_DEBUG:
6377 game_set_frametime(GS_STATE_EVENT_DEBUG);
6378 game_show_event_debug(flFrametime);
6382 case GS_STATE_STANDALONE_POSTGAME:
6383 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6384 multi_standalone_postgame_do();
6387 case GS_STATE_INITIAL_PLAYER_SELECT:
6388 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6392 case GS_STATE_MULTI_MISSION_SYNC:
6393 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6397 case GS_STATE_MULTI_START_GAME:
6398 game_set_frametime(GS_STATE_MULTI_START_GAME);
6399 multi_start_game_do();
6402 case GS_STATE_MULTI_HOST_OPTIONS:
6403 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6404 multi_host_options_do();
6407 case GS_STATE_END_OF_CAMPAIGN:
6408 mission_campaign_end_do();
6411 case GS_STATE_END_DEMO:
6412 game_set_frametime(GS_STATE_END_DEMO);
6413 end_demo_campaign_do();
6416 case GS_STATE_LOOP_BRIEF:
6417 game_set_frametime(GS_STATE_LOOP_BRIEF);
6421 } // end switch(gs_current_state)
6425 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6426 int game_do_ram_check(int ram_in_bytes)
6428 if ( ram_in_bytes < 30*1024*1024 ) {
6429 int allowed_to_run = 1;
6430 if ( ram_in_bytes < 25*1024*1024 ) {
6435 int Freespace_total_ram_MB;
6436 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6438 if ( allowed_to_run ) {
6440 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);
6444 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6445 if ( msgbox_rval == IDCANCEL ) {
6452 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);
6454 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6465 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6466 // If so, copy it over and remove the update directory.
6467 void game_maybe_update_launcher(char *exe_dir)
6470 char src_filename[MAX_PATH];
6471 char dest_filename[MAX_PATH];
6473 strcpy(src_filename, exe_dir);
6474 strcat(src_filename, NOX("\\update\\freespace.exe"));
6476 strcpy(dest_filename, exe_dir);
6477 strcat(dest_filename, NOX("\\freespace.exe"));
6479 // see if src_filename exists
6481 fp = fopen(src_filename, "rb");
6487 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6489 // copy updated freespace.exe to freespace exe dir
6490 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6491 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 );
6495 // delete the file in the update directory
6496 DeleteFile(src_filename);
6498 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6499 char update_dir[MAX_PATH];
6500 strcpy(update_dir, exe_dir);
6501 strcat(update_dir, NOX("\\update"));
6502 RemoveDirectory(update_dir);
6508 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6512 int sub_total_destroyed = 0;
6516 // get the total for all his children
6517 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6518 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6521 // find the # of faces for this _individual_ object
6522 total = submodel_get_num_polys(model_num, sm);
6523 if(strstr(pm->submodel[sm].name, "-destroyed")){
6524 sub_total_destroyed = total;
6528 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6531 *out_total += total + sub_total;
6532 *out_destroyed_total += sub_total_destroyed;
6535 #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);
6536 void game_spew_pof_info()
6538 char *pof_list[1000];
6541 int idx, model_num, i, j;
6543 int total, root_total, model_total, destroyed_total, counted;
6547 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6549 // spew info on all the pofs
6555 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6560 for(idx=0; idx<num_files; idx++, counted++){
6561 sprintf(str, "%s.pof", pof_list[idx]);
6562 model_num = model_load(str, 0, NULL);
6564 pm = model_get(model_num);
6566 // if we have a real model
6571 // go through and print all raw submodels
6572 cfputs("RAW\n", out);
6575 for (i=0; i<pm->n_models; i++) {
6576 total = submodel_get_num_polys(model_num, i);
6578 model_total += total;
6579 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6582 sprintf(str, "Model total %d\n", model_total);
6585 // now go through and do it by LOD
6586 cfputs("BY LOD\n\n", out);
6587 for(i=0; i<pm->n_detail_levels; i++){
6588 sprintf(str, "LOD %d\n", i);
6592 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6594 destroyed_total = 0;
6595 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6596 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6599 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6602 sprintf(str, "TOTAL: %d\n", total + root_total);
6604 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6606 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6609 cfputs("------------------------------------------------------------------------\n\n", out);
6613 if(counted >= MAX_POLYGON_MODELS - 5){
6626 game_spew_pof_info();
6629 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6634 // Don't let more than one instance of Freespace run.
6635 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6637 SetForegroundWindow(hwnd);
6642 // Find out how much RAM is on this machine
6645 ms.dwLength = sizeof(MEMORYSTATUS);
6646 GlobalMemoryStatus(&ms);
6647 Freespace_total_ram = ms.dwTotalPhys;
6649 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6653 if ( ms.dwTotalVirtual < 1024 ) {
6654 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6658 if (!vm_init(24*1024*1024)) {
6659 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 );
6663 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6665 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);
6675 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6676 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6677 seem worth bothering with.
6681 lResult = RegOpenKeyEx(
6682 HKEY_LOCAL_MACHINE, // Where it is
6683 "Software\\Microsoft\\DirectX", // name of key
6684 NULL, // DWORD reserved
6685 KEY_QUERY_VALUE, // Allows all changes
6686 &hKey // Location to store key
6689 if (lResult == ERROR_SUCCESS) {
6691 DWORD dwType, dwLen;
6694 lResult = RegQueryValueEx(
6695 hKey, // Handle to key
6696 "Version", // The values name
6697 NULL, // DWORD reserved
6698 &dwType, // What kind it is
6699 (ubyte *) version, // value to set
6700 &dwLen // How many bytes to set
6703 if (lResult == ERROR_SUCCESS) {
6704 dx_version = atoi(strstr(version, ".") + 1);
6708 DWORD dwType, dwLen;
6711 lResult = RegQueryValueEx(
6712 hKey, // Handle to key
6713 "InstalledVersion", // The values name
6714 NULL, // DWORD reserved
6715 &dwType, // What kind it is
6716 (ubyte *) &val, // value to set
6717 &dwLen // How many bytes to set
6720 if (lResult == ERROR_SUCCESS) {
6728 if (dx_version < 3) {
6729 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6730 "latest version of DirectX at:\n\n"
6731 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6733 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6734 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6739 //=====================================================
6740 // Make sure we're running in the right directory.
6744 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6745 char *p = exe_dir + strlen(exe_dir);
6747 // chop off the filename
6748 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6754 if ( strlen(exe_dir) > 0 ) {
6755 SetCurrentDirectory(exe_dir);
6758 // check for updated freespace.exe
6759 game_maybe_update_launcher(exe_dir);
6767 extern void windebug_memwatch_init();
6768 windebug_memwatch_init();
6772 parse_cmdline(szCmdLine);
6774 #ifdef STANDALONE_ONLY_BUILD
6776 nprintf(("Network", "Standalone running"));
6779 nprintf(("Network", "Standalone running"));
6787 // maybe spew pof stuff
6788 if(Cmdline_spew_pof_info){
6789 game_spew_pof_info();
6794 // non-demo, non-standalone, play the intro movie
6799 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) ){
6801 #if defined(OEM_BUILD)
6802 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6804 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6805 #endif // defined(OEM_BUILD)
6810 if ( !Is_standalone ) {
6812 // release -- movies always play
6815 // 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
6817 // movie_play( NOX("intro.mve"), 0 );
6819 // debug version, movie will only play with -showmovies
6820 #elif !defined(NDEBUG)
6823 // movie_play( NOX("intro.mve"), 0);
6826 if ( Cmdline_show_movies )
6827 movie_play( NOX("intro.mve"), 0 );
6836 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6838 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6842 // only important for non THREADED mode
6845 state = gameseq_process_events();
6846 if ( state == GS_STATE_QUIT_GAME ){
6853 demo_upsell_show_screens();
6855 #elif defined(OEM_BUILD)
6856 // show upsell screens on exit
6857 oem_upsell_show_screens();
6864 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6870 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6872 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6874 // Do nothing here - RecordExceptionInfo() has already done
6875 // everything that is needed. Actually this code won't even
6876 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6877 // the __except clause.
6883 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6884 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6888 // launcher the fslauncher program on exit
6889 void game_launch_launcher_on_exit()
6893 PROCESS_INFORMATION pi;
6894 char cmd_line[2048];
6895 char original_path[1024] = "";
6897 memset( &si, 0, sizeof(STARTUPINFO) );
6901 _getcwd(original_path, 1023);
6903 // set up command line
6904 strcpy(cmd_line, original_path);
6905 strcat(cmd_line, "\\");
6906 strcat(cmd_line, LAUNCHER_FNAME);
6907 strcat(cmd_line, " -straight_to_update");
6909 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6910 cmd_line, // pointer to command line string
6911 NULL, // pointer to process security attributes
6912 NULL, // pointer to thread security attributes
6913 FALSE, // handle inheritance flag
6914 CREATE_DEFAULT_ERROR_MODE, // creation flags
6915 NULL, // pointer to new environment block
6916 NULL, // pointer to current directory name
6917 &si, // pointer to STARTUPINFO
6918 &pi // pointer to PROCESS_INFORMATION
6920 // to eliminate build warnings
6930 // This function is called when FreeSpace terminates normally.
6932 void game_shutdown(void)
6938 // don't ever flip a page on the standalone!
6939 if(!(Game_mode & GM_STANDALONE_SERVER)){
6945 // if the player has left the "player select" screen and quit the game without actually choosing
6946 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6947 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6951 // load up common multiplayer icons
6952 multi_unload_common_icons();
6954 shockwave_close(); // release any memory used by shockwave system
6955 fireball_close(); // free fireball system
6956 ship_close(); // free any memory that was allocated for the ships
6957 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6958 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6959 bm_unload_all(); // free bitmaps
6960 mission_campaign_close(); // close out the campaign stuff
6961 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6963 #ifdef MULTI_USE_LAG
6967 // the menu close functions will unload the bitmaps if they were displayed during the game
6968 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6971 training_menu_close();
6974 extern void joy_close();
6977 audiostream_close();
6979 event_music_close();
6983 // HACKITY HACK HACK
6984 // if this flag is set, we should be firing up the launcher when exiting freespace
6985 extern int Multi_update_fireup_launcher_on_exit;
6986 if(Multi_update_fireup_launcher_on_exit){
6987 game_launch_launcher_on_exit();
6991 // game_stop_looped_sounds()
6993 // This function will call the appropriate stop looped sound functions for those
6994 // modules which use looping sounds. It is not enough just to stop a looping sound
6995 // at the DirectSound level, the game is keeping track of looping sounds, and this
6996 // function is used to inform the game that looping sounds are being halted.
6998 void game_stop_looped_sounds()
7000 hud_stop_looped_locking_sounds();
7001 hud_stop_looped_engine_sounds();
7002 afterburner_stop_sounds();
7003 player_stop_looped_sounds();
7004 obj_snd_stop_all(); // stop all object-linked persistant sounds
7005 game_stop_subspace_ambient_sound();
7006 snd_stop(Radar_static_looping);
7007 Radar_static_looping = -1;
7008 snd_stop(Target_static_looping);
7009 shipfx_stop_engine_wash_sound();
7010 Target_static_looping = -1;
7013 //////////////////////////////////////////////////////////////////////////
7015 // Code for supporting an animating mouse pointer
7018 //////////////////////////////////////////////////////////////////////////
7020 typedef struct animating_obj
7029 static animating_obj Animating_mouse;
7031 // ----------------------------------------------------------------------------
7032 // init_animating_pointer()
7034 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7035 // gets properly initialized
7037 void init_animating_pointer()
7039 Animating_mouse.first_frame = -1;
7040 Animating_mouse.num_frames = 0;
7041 Animating_mouse.current_frame = -1;
7042 Animating_mouse.time = 0.0f;
7043 Animating_mouse.elapsed_time = 0.0f;
7046 // ----------------------------------------------------------------------------
7047 // load_animating_pointer()
7049 // Called at game init to load in the frames for the animating mouse pointer
7051 // input: filename => filename of animation file that holds the animation
7053 void load_animating_pointer(char *filename, int dx, int dy)
7058 init_animating_pointer();
7060 am = &Animating_mouse;
7061 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7062 if ( am->first_frame == -1 )
7063 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7064 am->current_frame = 0;
7065 am->time = am->num_frames / i2fl(fps);
7068 // ----------------------------------------------------------------------------
7069 // unload_animating_pointer()
7071 // Called at game shutdown to free the memory used to store the animation frames
7073 void unload_animating_pointer()
7078 am = &Animating_mouse;
7079 for ( i = 0; i < am->num_frames; i++ ) {
7080 Assert( (am->first_frame+i) >= 0 );
7081 bm_release(am->first_frame + i);
7084 am->first_frame = -1;
7086 am->current_frame = -1;
7089 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7090 void game_render_mouse(float frametime)
7095 // if animating cursor exists, play the next frame
7096 am = &Animating_mouse;
7097 if ( am->first_frame != -1 ) {
7098 mouse_get_pos(&mx, &my);
7099 am->elapsed_time += frametime;
7100 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7101 if ( am->current_frame >= am->num_frames ) {
7102 am->current_frame = 0;
7103 am->elapsed_time = 0.0f;
7105 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7109 // ----------------------------------------------------------------------------
7110 // game_maybe_draw_mouse()
7112 // determines whether to draw the mouse pointer at all, and what frame of
7113 // animation to use if the mouse is animating
7115 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7117 // input: frametime => elapsed frame time in seconds since last call
7119 void game_maybe_draw_mouse(float frametime)
7123 game_state = gameseq_get_state();
7125 switch ( game_state ) {
7126 case GS_STATE_GAME_PAUSED:
7127 // case GS_STATE_MULTI_PAUSED:
7128 case GS_STATE_GAME_PLAY:
7129 case GS_STATE_DEATH_DIED:
7130 case GS_STATE_DEATH_BLEW_UP:
7131 if ( popup_active() || popupdead_is_active() ) {
7143 if ( !Mouse_hidden )
7144 game_render_mouse(frametime);
7148 void game_do_training_checks()
7152 waypoint_list *wplp;
7154 if (Training_context & TRAINING_CONTEXT_SPEED) {
7155 s = (int) Player_obj->phys_info.fspeed;
7156 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7157 if (!Training_context_speed_set) {
7158 Training_context_speed_set = 1;
7159 Training_context_speed_timestamp = timestamp();
7163 Training_context_speed_set = 0;
7166 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7167 wplp = &Waypoint_lists[Training_context_path];
7168 if (wplp->count > Training_context_goal_waypoint) {
7169 i = Training_context_goal_waypoint;
7171 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7172 if (d <= Training_context_distance) {
7173 Training_context_at_waypoint = i;
7174 if (Training_context_goal_waypoint == i) {
7175 Training_context_goal_waypoint++;
7176 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7183 if (i == wplp->count)
7186 } while (i != Training_context_goal_waypoint);
7190 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7191 Players_target = Player_ai->target_objnum;
7192 Players_targeted_subsys = Player_ai->targeted_subsys;
7193 Players_target_timestamp = timestamp();
7197 /////////// Following is for event debug view screen
7201 #define EVENT_DEBUG_MAX 5000
7202 #define EVENT_DEBUG_EVENT 0x8000
7204 int Event_debug_index[EVENT_DEBUG_MAX];
7207 void game_add_event_debug_index(int n, int indent)
7209 if (ED_count < EVENT_DEBUG_MAX)
7210 Event_debug_index[ED_count++] = n | (indent << 16);
7213 void game_add_event_debug_sexp(int n, int indent)
7218 if (Sexp_nodes[n].first >= 0) {
7219 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7220 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7224 game_add_event_debug_index(n, indent);
7225 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7226 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7228 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7231 void game_event_debug_init()
7236 for (e=0; e<Num_mission_events; e++) {
7237 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7238 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7242 void game_show_event_debug(float frametime)
7246 int font_height, font_width;
7248 static int scroll_offset = 0;
7250 k = game_check_key();
7256 if (scroll_offset < 0)
7266 scroll_offset -= 20;
7267 if (scroll_offset < 0)
7272 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7276 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7282 gr_set_color_fast(&Color_bright);
7284 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7286 gr_set_color_fast(&Color_normal);
7288 gr_get_string_size(&font_width, &font_height, NOX("test"));
7289 y_max = gr_screen.max_h - font_height - 5;
7293 while (k < ED_count) {
7294 if (y_index > y_max)
7297 z = Event_debug_index[k];
7298 if (z & EVENT_DEBUG_EVENT) {
7300 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7301 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7302 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7303 Mission_events[z].repeat_count, Mission_events[z].interval);
7311 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7312 switch (Sexp_nodes[z & 0x7fff].value) {
7314 strcat(buf, NOX(" (True)"));
7318 strcat(buf, NOX(" (False)"));
7321 case SEXP_KNOWN_TRUE:
7322 strcat(buf, NOX(" (Always true)"));
7325 case SEXP_KNOWN_FALSE:
7326 strcat(buf, NOX(" (Always false)"));
7329 case SEXP_CANT_EVAL:
7330 strcat(buf, NOX(" (Can't eval)"));
7334 case SEXP_NAN_FOREVER:
7335 strcat(buf, NOX(" (Not a number)"));
7340 gr_printf(10, y_index, buf);
7341 y_index += font_height;
7354 extern int Tmap_npixels;
7356 int Tmap_num_too_big = 0;
7357 int Num_models_needing_splitting = 0;
7359 void Time_model( int modelnum )
7361 // mprintf(( "Timing ship '%s'\n", si->name ));
7363 vector eye_pos, model_pos;
7364 matrix eye_orient, model_orient;
7366 polymodel *pm = model_get( modelnum );
7368 int l = strlen(pm->filename);
7370 if ( (l == '/') || (l=='\\') || (l==':')) {
7376 char *pof_file = &pm->filename[l];
7378 int model_needs_splitting = 0;
7380 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7382 for (i=0; i<pm->n_textures; i++ ) {
7383 char filename[1024];
7386 int bmp_num = pm->original_textures[i];
7387 if ( bmp_num > -1 ) {
7388 bm_get_palette(pm->original_textures[i], pal, filename );
7390 bm_get_info( pm->original_textures[i],&w, &h );
7393 if ( (w > 512) || (h > 512) ) {
7394 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7396 model_needs_splitting++;
7399 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7403 if ( model_needs_splitting ) {
7404 Num_models_needing_splitting++;
7406 eye_orient = model_orient = vmd_identity_matrix;
7407 eye_pos = model_pos = vmd_zero_vector;
7409 eye_pos.z = -pm->rad*2.0f;
7411 vector eye_to_model;
7413 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7414 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7416 fix t1 = timer_get_fixed_seconds();
7419 ta.p = ta.b = ta.h = 0.0f;
7424 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7426 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7428 modelstats_num_polys = modelstats_num_verts = 0;
7430 while( ta.h < PI2 ) {
7433 vm_angles_2_matrix(&m1, &ta );
7434 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7441 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7443 model_clear_instance( modelnum );
7444 model_set_detail_level(0); // use highest detail level
7445 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7453 int k = key_inkey();
7454 if ( k == KEY_ESC ) {
7459 fix t2 = timer_get_fixed_seconds();
7461 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7462 //bitmaps_used_this_frame /= framecount;
7464 modelstats_num_polys /= framecount;
7465 modelstats_num_verts /= framecount;
7467 Tmap_npixels /=framecount;
7470 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7471 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 );
7472 // 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 );
7478 int Time_models = 0;
7479 DCF_BOOL( time_models, Time_models );
7481 void Do_model_timings_test()
7485 if ( !Time_models ) return;
7487 mprintf(( "Timing models!\n" ));
7491 ubyte model_used[MAX_POLYGON_MODELS];
7492 int model_id[MAX_POLYGON_MODELS];
7493 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7498 for (i=0; i<Num_ship_types; i++ ) {
7499 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7501 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7502 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7505 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7506 if ( !Texture_fp ) return;
7508 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7509 if ( !Time_fp ) return;
7511 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7512 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7514 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7515 if ( model_used[i] ) {
7516 Time_model( model_id[i] );
7520 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7521 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7530 // Call this function when you want to inform the player that a feature is not
7531 // enabled in the DEMO version of FreSpace
7532 void game_feature_not_in_demo_popup()
7534 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7537 // format the specified time (fixed point) into a nice string
7538 void game_format_time(fix m_time,char *time_str)
7541 int hours,minutes,seconds;
7544 mtime = f2fl(m_time);
7546 // get the hours, minutes and seconds
7547 hours = (int)(mtime / 3600.0f);
7549 mtime -= (3600.0f * (float)hours);
7551 seconds = (int)mtime%60;
7552 minutes = (int)mtime/60;
7554 // print the hour if necessary
7556 sprintf(time_str,XSTR( "%d:", 201),hours);
7557 // if there are less than 10 minutes, print a leading 0
7559 strcpy(tmp,NOX("0"));
7560 strcat(time_str,tmp);
7564 // print the minutes
7566 sprintf(tmp,XSTR( "%d:", 201),minutes);
7567 strcat(time_str,tmp);
7569 sprintf(time_str,XSTR( "%d:", 201),minutes);
7572 // print the seconds
7574 strcpy(tmp,NOX("0"));
7575 strcat(time_str,tmp);
7577 sprintf(tmp,"%d",seconds);
7578 strcat(time_str,tmp);
7581 // Stuff version string in *str.
7582 void get_version_string(char *str)
7585 if ( FS_VERSION_BUILD == 0 ) {
7586 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7588 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7591 #if defined (FS2_DEMO)
7593 #elif defined (OEM_BUILD)
7594 strcat(str, " (OEM)");
7600 char myname[_MAX_PATH];
7601 int namelen, major, minor, build, waste;
7602 unsigned int buf_size;
7608 // Find my EXE file name
7609 hMod = GetModuleHandle(NULL);
7610 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7612 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7613 infop = (char *)malloc(version_size);
7614 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7616 // get the product version
7617 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7618 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7620 sprintf(str,"Dv%d.%02d",major, minor);
7622 sprintf(str,"v%d.%02d",major, minor);
7627 void get_version_string_short(char *str)
7629 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7632 // ----------------------------------------------------------------
7634 // OEM UPSELL SCREENS BEGIN
7636 // ----------------------------------------------------------------
7637 #if defined(OEM_BUILD)
7639 #define NUM_OEM_UPSELL_SCREENS 3
7640 #define OEM_UPSELL_SCREEN_DELAY 10000
7642 static int Oem_upsell_bitmaps_loaded = 0;
7643 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7644 static int Oem_upsell_screen_number = 0;
7645 static int Oem_upsell_show_next_bitmap_time;
7648 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7661 static int Oem_normal_cursor = -1;
7662 static int Oem_web_cursor = -1;
7663 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7664 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7666 void oem_upsell_next_screen()
7668 Oem_upsell_screen_number++;
7669 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7670 // extra long delay, mouse shown on last upsell
7671 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7675 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7679 void oem_upsell_load_bitmaps()
7683 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7684 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7688 void oem_upsell_unload_bitmaps()
7692 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7693 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7694 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7699 Oem_upsell_bitmaps_loaded = 0;
7702 // clickable hotspot on 3rd OEM upsell screen
7703 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7705 28, 350, 287, 96 // x, y, w, h
7708 45, 561, 460, 152 // x, y, w, h
7712 void oem_upsell_show_screens()
7714 int current_time, k;
7717 if ( !Oem_upsell_bitmaps_loaded ) {
7718 oem_upsell_load_bitmaps();
7719 Oem_upsell_bitmaps_loaded = 1;
7722 // may use upsell screens more than once
7723 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7724 Oem_upsell_screen_number = 0;
7730 int nframes; // used to pass, not really needed (should be 1)
7731 Oem_normal_cursor = gr_get_cursor_bitmap();
7732 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7733 Assert(Oem_web_cursor >= 0);
7734 if (Oem_web_cursor < 0) {
7735 Oem_web_cursor = Oem_normal_cursor;
7740 //oem_reset_trailer_timer();
7742 current_time = timer_get_milliseconds();
7747 // advance screen on keypress or timeout
7748 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7749 oem_upsell_next_screen();
7752 // check if we are done
7753 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7754 Oem_upsell_screen_number--;
7757 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7762 // show me the upsell
7763 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7764 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7768 // if this is the 3rd upsell, make it clickable, d00d
7769 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7771 int button_state = mouse_get_pos(&mx, &my);
7772 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])
7773 && (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]) )
7776 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7779 if (button_state & MOUSE_LEFT_BUTTON) {
7781 multi_pxo_url(OEM_UPSELL_URL);
7785 // switch cursor back to normal one
7786 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7791 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7801 oem_upsell_unload_bitmaps();
7803 // switch cursor back to normal one
7804 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7808 #endif // defined(OEM_BUILD)
7809 // ----------------------------------------------------------------
7811 // OEM UPSELL SCREENS END
7813 // ----------------------------------------------------------------
7817 // ----------------------------------------------------------------
7819 // DEMO UPSELL SCREENS BEGIN
7821 // ----------------------------------------------------------------
7825 //#define NUM_DEMO_UPSELL_SCREENS 4
7827 #define NUM_DEMO_UPSELL_SCREENS 2
7828 #define DEMO_UPSELL_SCREEN_DELAY 3000
7830 static int Demo_upsell_bitmaps_loaded = 0;
7831 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7832 static int Demo_upsell_screen_number = 0;
7833 static int Demo_upsell_show_next_bitmap_time;
7836 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7849 void demo_upsell_next_screen()
7851 Demo_upsell_screen_number++;
7852 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7853 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7855 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7859 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7860 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7861 #ifndef HARDWARE_ONLY
7862 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7869 void demo_upsell_load_bitmaps()
7873 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7874 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7878 void demo_upsell_unload_bitmaps()
7882 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7883 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7884 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7889 Demo_upsell_bitmaps_loaded = 0;
7892 void demo_upsell_show_screens()
7894 int current_time, k;
7897 if ( !Demo_upsell_bitmaps_loaded ) {
7898 demo_upsell_load_bitmaps();
7899 Demo_upsell_bitmaps_loaded = 1;
7902 // may use upsell screens more than once
7903 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7904 Demo_upsell_screen_number = 0;
7911 demo_reset_trailer_timer();
7913 current_time = timer_get_milliseconds();
7920 // don't time out, wait for keypress
7922 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7923 demo_upsell_next_screen();
7928 demo_upsell_next_screen();
7931 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7932 Demo_upsell_screen_number--;
7935 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7940 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7941 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7946 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7956 demo_upsell_unload_bitmaps();
7961 // ----------------------------------------------------------------
7963 // DEMO UPSELL SCREENS END
7965 // ----------------------------------------------------------------
7968 // ----------------------------------------------------------------
7970 // Subspace Ambient Sound START
7972 // ----------------------------------------------------------------
7974 static int Subspace_ambient_left_channel = -1;
7975 static int Subspace_ambient_right_channel = -1;
7978 void game_start_subspace_ambient_sound()
7980 if ( Subspace_ambient_left_channel < 0 ) {
7981 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7984 if ( Subspace_ambient_right_channel < 0 ) {
7985 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7989 void game_stop_subspace_ambient_sound()
7991 if ( Subspace_ambient_left_channel >= 0 ) {
7992 snd_stop(Subspace_ambient_left_channel);
7993 Subspace_ambient_left_channel = -1;
7996 if ( Subspace_ambient_right_channel >= 0 ) {
7997 snd_stop(Subspace_ambient_right_channel);
7998 Subspace_ambient_right_channel = -1;
8002 // ----------------------------------------------------------------
8004 // Subspace Ambient Sound END
8006 // ----------------------------------------------------------------
8008 // ----------------------------------------------------------------
8010 // CDROM detection code START
8012 // ----------------------------------------------------------------
8014 #define CD_SIZE_72_MINUTE_MAX (697000000)
8016 uint game_get_cd_used_space(char *path)
8020 char use_path[512] = "";
8021 char sub_path[512] = "";
8022 WIN32_FIND_DATA find;
8025 // recurse through all files and directories
8026 strcpy(use_path, path);
8027 strcat(use_path, "*.*");
8028 find_handle = FindFirstFile(use_path, &find);
8031 if(find_handle == INVALID_HANDLE_VALUE){
8037 // subdirectory. make sure to ignore . and ..
8038 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8040 strcpy(sub_path, path);
8041 strcat(sub_path, find.cFileName);
8042 strcat(sub_path, "\\");
8043 total += game_get_cd_used_space(sub_path);
8045 total += (uint)find.nFileSizeLow;
8047 } while(FindNextFile(find_handle, &find));
8050 FindClose(find_handle);
8062 // if volume_name is non-null, the CD name must match that
8063 int find_freespace_cd(char *volume_name)
8066 char oldpath[MAX_PATH];
8070 int volume_match = 0;
8074 GetCurrentDirectory(MAX_PATH, oldpath);
8076 for (i = 0; i < 26; i++)
8082 path[0] = (char)('A'+i);
8083 if (GetDriveType(path) == DRIVE_CDROM) {
8085 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8086 nprintf(("CD", "CD volume: %s\n", volume));
8088 // check for any CD volume
8089 int volume1_present = 0;
8090 int volume2_present = 0;
8091 int volume3_present = 0;
8093 char full_check[512] = "";
8095 // look for setup.exe
8096 strcpy(full_check, path);
8097 strcat(full_check, "setup.exe");
8098 find_handle = _findfirst(full_check, &find);
8099 if(find_handle != -1){
8100 volume1_present = 1;
8101 _findclose(find_handle);
8104 // look for intro.mve
8105 strcpy(full_check, path);
8106 strcat(full_check, "intro.mve");
8107 find_handle = _findfirst(full_check, &find);
8108 if(find_handle != -1){
8109 volume2_present = 1;
8110 _findclose(find_handle);
8113 // look for endpart1.mve
8114 strcpy(full_check, path);
8115 strcat(full_check, "endpart1.mve");
8116 find_handle = _findfirst(full_check, &find);
8117 if(find_handle != -1){
8118 volume3_present = 1;
8119 _findclose(find_handle);
8122 // see if we have the specific CD we're looking for
8123 if ( volume_name ) {
8125 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8129 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8133 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8137 if ( volume1_present || volume2_present || volume3_present ) {
8142 // 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
8143 if ( volume_match ){
8145 // 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
8146 if(volume2_present || volume3_present) {
8147 // first step - check to make sure its a cdrom
8148 if(GetDriveType(path) != DRIVE_CDROM){
8152 #if !defined(OEM_BUILD)
8153 // oem not on 80 min cds, so dont check tha size
8155 uint used_space = game_get_cd_used_space(path);
8156 if(used_space < CD_SIZE_72_MINUTE_MAX){
8159 #endif // !defined(OEM_BUILD)
8167 #endif // RELEASE_REAL
8173 SetCurrentDirectory(oldpath);
8182 int set_cdrom_path(int drive_num)
8186 if (drive_num < 0) { //no CD
8188 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8191 strcpy(Game_CDROM_dir,""); //set directory
8195 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8211 i = find_freespace_cd();
8213 rval = set_cdrom_path(i);
8217 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8219 nprintf(("CD", "FreeSpace CD not found\n"));
8227 int Last_cd_label_found = 0;
8228 char Last_cd_label[256];
8230 int game_cd_changed()
8237 if ( strlen(Game_CDROM_dir) == 0 ) {
8241 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8243 if ( found != Last_cd_label_found ) {
8244 Last_cd_label_found = found;
8246 mprintf(( "CD '%s' was inserted\n", label ));
8249 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8253 if ( Last_cd_label_found ) {
8254 if ( !stricmp( Last_cd_label, label )) {
8255 //mprintf(( "CD didn't change\n" ));
8257 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8261 // none found before, none found now.
8262 //mprintf(( "still no CD...\n" ));
8266 Last_cd_label_found = found;
8268 strcpy( Last_cd_label, label );
8270 strcpy( Last_cd_label, "" );
8279 // check if _any_ FreeSpace2 CDs are in the drive
8280 // return: 1 => CD now in drive
8281 // 0 => Could not find CD, they refuse to put it in the drive
8282 int game_do_cd_check(char *volume_name)
8284 #if !defined(GAME_CD_CHECK)
8290 int num_attempts = 0;
8291 int refresh_files = 0;
8293 int path_set_ok, popup_rval;
8295 cd_drive_num = find_freespace_cd(volume_name);
8296 path_set_ok = set_cdrom_path(cd_drive_num);
8297 if ( path_set_ok ) {
8299 if ( refresh_files ) {
8311 // no CD found, so prompt user
8312 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8314 if ( popup_rval != 1 ) {
8319 if ( num_attempts++ > 5 ) {
8330 // check if _any_ FreeSpace2 CDs are in the drive
8331 // return: 1 => CD now in drive
8332 // 0 => Could not find CD, they refuse to put it in the drive
8333 int game_do_cd_check_specific(char *volume_name, int cdnum)
8338 int num_attempts = 0;
8339 int refresh_files = 0;
8341 int path_set_ok, popup_rval;
8343 cd_drive_num = find_freespace_cd(volume_name);
8344 path_set_ok = set_cdrom_path(cd_drive_num);
8345 if ( path_set_ok ) {
8347 if ( refresh_files ) {
8358 // no CD found, so prompt user
8359 #if defined(DVD_MESSAGE_HACK)
8360 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8362 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8365 if ( popup_rval != 1 ) {
8370 if ( num_attempts++ > 5 ) {
8380 // only need to do this in RELEASE_REAL
8381 int game_do_cd_mission_check(char *filename)
8387 fs_builtin_mission *m = game_find_builtin_mission(filename);
8389 // check for changed CD
8390 if(game_cd_changed()){
8395 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8399 // not builtin, so do a general check (any FS2 CD will do)
8401 return game_do_cd_check();
8404 // does not have any CD requirement, do a general check
8405 if(strlen(m->cd_volume) <= 0){
8406 return game_do_cd_check();
8410 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8412 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8414 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8417 return game_do_cd_check();
8420 // did we find the cd?
8421 if(find_freespace_cd(m->cd_volume) >= 0){
8425 // make sure the volume exists
8426 int num_attempts = 0;
8427 int refresh_files = 0;
8429 int path_set_ok, popup_rval;
8431 cd_drive_num = find_freespace_cd(m->cd_volume);
8432 path_set_ok = set_cdrom_path(cd_drive_num);
8433 if ( path_set_ok ) {
8435 if ( refresh_files ) {
8442 // no CD found, so prompt user
8443 #if defined(DVD_MESSAGE_HACK)
8444 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8446 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8450 if ( popup_rval != 1 ) {
8455 if ( num_attempts++ > 5 ) {
8467 // ----------------------------------------------------------------
8469 // CDROM detection code END
8471 // ----------------------------------------------------------------
8473 // ----------------------------------------------------------------
8474 // SHIPS TBL VERIFICATION STUFF
8477 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8478 #define NUM_SHIPS_TBL_CHECKSUMS 1
8480 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8481 -463907578, // US - beta 1
8482 1696074201, // FS2 demo
8485 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8486 // -1022810006, // 1.0 FULL
8487 -1254285366 // 1.2 FULL (German)
8490 void verify_ships_tbl()
8494 Game_ships_tbl_valid = 1;
8500 // detect if the packfile exists
8501 CFILE *detect = cfopen("ships.tbl", "rb");
8502 Game_ships_tbl_valid = 0;
8506 Game_ships_tbl_valid = 0;
8510 // get the long checksum of the file
8512 cfseek(detect, 0, SEEK_SET);
8513 cf_chksum_long(detect, &file_checksum);
8517 // now compare the checksum/filesize against known #'s
8518 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8519 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8520 Game_ships_tbl_valid = 1;
8527 DCF(shipspew, "display the checksum for the current ships.tbl")
8530 CFILE *detect = cfopen("ships.tbl", "rb");
8531 // get the long checksum of the file
8533 cfseek(detect, 0, SEEK_SET);
8534 cf_chksum_long(detect, &file_checksum);
8537 dc_printf("%d", file_checksum);
8540 // ----------------------------------------------------------------
8541 // WEAPONS TBL VERIFICATION STUFF
8544 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8545 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8547 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8548 141718090, // US - beta 1
8549 -266420030, // demo 1
8552 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8553 // 399297860, // 1.0 FULL
8554 -553984927 // 1.2 FULL (german)
8557 void verify_weapons_tbl()
8561 Game_weapons_tbl_valid = 1;
8567 // detect if the packfile exists
8568 CFILE *detect = cfopen("weapons.tbl", "rb");
8569 Game_weapons_tbl_valid = 0;
8573 Game_weapons_tbl_valid = 0;
8577 // get the long checksum of the file
8579 cfseek(detect, 0, SEEK_SET);
8580 cf_chksum_long(detect, &file_checksum);
8584 // now compare the checksum/filesize against known #'s
8585 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8586 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8587 Game_weapons_tbl_valid = 1;
8594 DCF(wepspew, "display the checksum for the current weapons.tbl")
8597 CFILE *detect = cfopen("weapons.tbl", "rb");
8598 // get the long checksum of the file
8600 cfseek(detect, 0, SEEK_SET);
8601 cf_chksum_long(detect, &file_checksum);
8604 dc_printf("%d", file_checksum);
8607 // if the game is running using hacked data
8608 int game_hacked_data()
8611 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8619 void display_title_screen()
8621 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8622 ///int title_bitmap;
8625 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8626 if (title_bitmap == -1) {
8631 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8632 extern void d3d_start_frame();
8637 gr_set_bitmap(title_bitmap);
8643 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8644 extern void d3d_stop_frame();
8651 bm_unload(title_bitmap);
8652 #endif // FS2_DEMO || OEM_BUILD
8655 // return true if the game is running with "low memory", which is less than 48MB
8656 bool game_using_low_mem()
8658 if (Use_low_mem == 0) {