2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.6 2002/05/28 06:28:20 theoddone33
11 * Filesystem mods, actually reads some data files now
13 * Revision 1.5 2002/05/28 04:07:28 theoddone33
14 * New graphics stubbing arrangement
16 * Revision 1.4 2002/05/27 22:46:52 theoddone33
17 * Remove more undefined symbols
19 * Revision 1.3 2002/05/26 23:31:18 relnev
20 * added a few files that needed to be compiled
22 * freespace.cpp: now compiles
24 * Revision 1.2 2002/05/07 03:16:44 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:09 root
31 * 201 6/16/00 3:15p Jefff
32 * sim of the year dvd version changes, a few german soty localization
35 * 200 11/03/99 11:06a Jefff
38 * 199 10/26/99 5:07p Jamest
39 * fixed jeffs dumb debug code
41 * 198 10/25/99 5:53p Jefff
42 * call control_config_common_init() on startup
44 * 197 10/14/99 10:18a Daveb
45 * Fixed incorrect CD checking problem on standalone server.
47 * 196 10/13/99 9:22a Daveb
48 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
49 * related to movies. Fixed launcher spawning from PXO screen.
51 * 195 10/06/99 11:05a Jefff
52 * new oem upsell 3 hotspot coords
54 * 194 10/06/99 10:31a Jefff
57 * 193 10/01/99 9:10a Daveb
60 * 192 9/15/99 4:57a Dave
61 * Updated ships.tbl checksum
63 * 191 9/15/99 3:58a Dave
64 * Removed framerate warning at all times.
66 * 190 9/15/99 3:16a Dave
67 * Remove mt-011.fs2 from the builtin mission list.
69 * 189 9/15/99 1:45a Dave
70 * Don't init joystick on standalone. Fixed campaign mode on standalone.
71 * Fixed no-score-report problem in TvT
73 * 188 9/14/99 6:08a Dave
74 * Updated (final) single, multi, and campaign list.
76 * 187 9/14/99 3:26a Dave
77 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
78 * respawn-too-early problem. Made a few crash points safe.
80 * 186 9/13/99 4:52p Dave
83 * 185 9/12/99 8:09p Dave
84 * Fixed problem where skip-training button would cause mission messages
85 * not to get paged out for the current mission.
87 * 184 9/10/99 11:53a Dave
88 * Shutdown graphics before sound to eliminate apparent lockups when
89 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
91 * 183 9/09/99 11:40p Dave
92 * Handle an Assert() in beam code. Added supernova sounds. Play the right
93 * 2 end movies properly, based upon what the player did in the mission.
95 * 182 9/08/99 10:29p Dave
96 * Make beam sound pausing and unpausing much safer.
98 * 181 9/08/99 10:01p Dave
99 * Make sure game won't run in a drive's root directory. Make sure
100 * standalone routes suqad war messages properly to the host.
102 * 180 9/08/99 3:22p Dave
103 * Updated builtin mission list.
105 * 179 9/08/99 12:01p Jefff
106 * fixed Game_builtin_mission_list typo on Training-2.fs2
108 * 178 9/08/99 9:48a Andsager
109 * Add force feedback for engine wash.
111 * 177 9/07/99 4:01p Dave
112 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
113 * does everything properly (setting up address when binding). Remove
114 * black rectangle background from UI_INPUTBOX.
116 * 176 9/13/99 2:40a Dave
117 * Comment in full 80 minute CD check for RELEASE_REAL builds.
119 * 175 9/06/99 6:38p Dave
120 * Improved CD detection code.
122 * 174 9/06/99 1:30a Dave
123 * Intermediate checkin. Started on enforcing CD-in-drive to play the
126 * 173 9/06/99 1:16a Dave
127 * Make sure the user sees the intro movie.
129 * 172 9/04/99 8:00p Dave
130 * Fixed up 1024 and 32 bit movie support.
132 * 171 9/03/99 1:32a Dave
133 * CD checking by act. Added support to play 2 cutscenes in a row
134 * seamlessly. Fixed super low level cfile bug related to files in the
135 * root directory of a CD. Added cheat code to set campaign mission # in
138 * 170 9/01/99 10:49p Dave
139 * Added nice SquadWar checkbox to the client join wait screen.
141 * 169 9/01/99 10:14a Dave
144 * 168 8/29/99 4:51p Dave
145 * Fixed damaged checkin.
147 * 167 8/29/99 4:18p Andsager
148 * New "burst" limit for friendly damage. Also credit more damage done
149 * against large friendly ships.
151 * 166 8/27/99 6:38p Alanl
152 * crush the blasted repeating messages bug
154 * 164 8/26/99 9:09p Dave
155 * Force framerate check in everything but a RELEASE_REAL build.
157 * 163 8/26/99 9:45a Dave
158 * First pass at easter eggs and cheats.
160 * 162 8/24/99 8:55p Dave
161 * Make sure nondimming pixels work properly in tech menu.
163 * 161 8/24/99 1:49a Dave
164 * Fixed client-side afterburner stuttering. Added checkbox for no version
165 * checking on PXO join. Made button info passing more friendly between
168 * 160 8/22/99 5:53p Dave
169 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
170 * instead of ship designations for multiplayer players.
172 * 159 8/22/99 1:19p Dave
173 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
174 * which d3d cards are detected.
176 * 158 8/20/99 2:09p Dave
177 * PXO banner cycling.
179 * 157 8/19/99 10:59a Dave
180 * Packet loss detection.
182 * 156 8/19/99 10:12a Alanl
183 * preload mission-specific messages on machines greater than 48MB
185 * 155 8/16/99 4:04p Dave
186 * Big honking checkin.
188 * 154 8/11/99 5:54p Dave
189 * Fixed collision problem. Fixed standalone ghost problem.
191 * 153 8/10/99 7:59p Jefff
194 * 152 8/10/99 6:54p Dave
195 * Mad optimizations. Added paging to the nebula effect.
197 * 151 8/10/99 3:44p Jefff
198 * loads Intelligence information on startup
200 * 150 8/09/99 3:47p Dave
201 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
202 * non-nebula missions.
204 * 149 8/09/99 2:21p Andsager
205 * Fix patching from multiplayer direct to launcher update tab.
207 * 148 8/09/99 10:36a Dave
208 * Version info for game.
210 * 147 8/06/99 9:46p Dave
211 * Hopefully final changes for the demo.
213 * 146 8/06/99 3:34p Andsager
214 * Make title version info "(D)" -> "D" show up nicely
216 * 145 8/06/99 2:59p Adamp
217 * Fixed NT launcher/update problem.
219 * 144 8/06/99 1:52p Dave
220 * Bumped up MAX_BITMAPS for the demo.
222 * 143 8/06/99 12:17p Andsager
223 * Demo: down to just 1 demo dog
225 * 142 8/05/99 9:39p Dave
226 * Yet another new checksum.
228 * 141 8/05/99 6:19p Dave
229 * New demo checksums.
231 * 140 8/05/99 5:31p Andsager
232 * Up demo version 1.01
234 * 139 8/05/99 4:22p Andsager
235 * No time limit on upsell screens. Reverse order of display of upsell
238 * 138 8/05/99 4:17p Dave
239 * Tweaks to client interpolation.
241 * 137 8/05/99 3:52p Danw
243 * 136 8/05/99 3:01p Danw
245 * 135 8/05/99 2:43a Anoop
246 * removed duplicate definition.
248 * 134 8/05/99 2:13a Dave
251 * 133 8/05/99 2:05a Dave
254 * 132 8/05/99 1:22a Andsager
257 * 131 8/04/99 9:51p Andsager
258 * Add title screen to demo
260 * 130 8/04/99 6:47p Jefff
261 * fixed link error resulting from #ifdefs
263 * 129 8/04/99 6:26p Dave
264 * Updated ship tbl checksum.
266 * 128 8/04/99 5:40p Andsager
267 * Add multiple demo dogs
269 * 127 8/04/99 5:36p Andsager
270 * Show upsell screens at end of demo campaign before returning to main
273 * 126 8/04/99 11:42a Danw
274 * tone down EAX reverb
276 * 125 8/04/99 11:23a Dave
277 * Updated demo checksums.
279 * 124 8/03/99 11:02p Dave
280 * Maybe fixed sync problems in multiplayer.
282 * 123 8/03/99 6:21p Jefff
285 * 122 8/03/99 3:44p Andsager
286 * Launch laucher if trying to run FS without first having configured
289 * 121 8/03/99 12:45p Dave
292 * 120 8/02/99 9:13p Dave
295 * 119 7/30/99 10:31p Dave
296 * Added comm menu to the configurable hud files.
298 * 118 7/30/99 5:17p Andsager
299 * first fs2demo checksums
301 * 117 7/29/99 3:09p Anoop
303 * 116 7/29/99 12:05a Dave
304 * Nebula speed optimizations.
306 * 115 7/27/99 8:59a Andsager
307 * Make major, minor version consistent for all builds. Only show major
308 * and minor for launcher update window.
310 * 114 7/26/99 5:50p Dave
311 * Revised ingame join. Better? We'll see....
313 * 113 7/26/99 5:27p Andsager
314 * Add training mission as builtin to demo build
316 * 112 7/24/99 1:54p Dave
317 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
320 * 111 7/22/99 4:00p Dave
321 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
323 * 110 7/21/99 8:10p Dave
324 * First run of supernova effect.
326 * 109 7/20/99 1:49p Dave
327 * Peter Drake build. Fixed some release build warnings.
329 * 108 7/19/99 2:26p Andsager
330 * set demo multiplayer missions
332 * 107 7/18/99 5:19p Dave
333 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
335 * 106 7/16/99 1:50p Dave
336 * 8 bit aabitmaps. yay.
338 * 105 7/15/99 3:07p Dave
339 * 32 bit detection support. Mouse coord commandline.
341 * 104 7/15/99 2:13p Dave
342 * Added 32 bit detection.
344 * 103 7/15/99 9:20a Andsager
345 * FS2_DEMO initial checkin
347 * 102 7/14/99 11:02a Dave
348 * Skill level default back to easy. Blech.
350 * 101 7/09/99 5:54p Dave
351 * Seperated cruiser types into individual types. Added tons of new
352 * briefing icons. Campaign screen.
354 * 100 7/08/99 4:43p Andsager
355 * New check for sparky_hi and print if not found.
357 * 99 7/08/99 10:53a Dave
358 * New multiplayer interpolation scheme. Not 100% done yet, but still
359 * better than the old way.
361 * 98 7/06/99 4:24p Dave
362 * Mid-level checkin. Starting on some potentially cool multiplayer
365 * 97 7/06/99 3:35p Andsager
366 * Allow movie to play before red alert mission.
368 * 96 7/03/99 5:50p Dave
369 * Make rotated bitmaps draw properly in padlock views.
371 * 95 7/02/99 9:55p Dave
372 * Player engine wash sound.
374 * 94 7/02/99 4:30p Dave
375 * Much more sophisticated lightning support.
377 * 93 6/29/99 7:52p Dave
378 * Put in exception handling in FS2.
380 * 92 6/22/99 9:37p Dave
381 * Put in pof spewing.
383 * 91 6/16/99 4:06p Dave
384 * New pilot info popup. Added new draw-bitmap-as-poly function.
386 * 90 6/15/99 1:56p Andsager
387 * For release builds, allow start up in high res only with
390 * 89 6/15/99 9:34a Dave
391 * Fixed key checking in single threaded version of the stamp notification
394 * 88 6/09/99 2:55p Andsager
395 * Allow multiple asteroid subtypes (of large, medium, small) and follow
398 * 87 6/08/99 1:14a Dave
399 * Multi colored hud test.
401 * 86 6/04/99 9:52a Dave
402 * Fixed some rendering problems.
404 * 85 6/03/99 10:15p Dave
405 * Put in temporary main hall screen.
407 * 84 6/02/99 6:18p Dave
408 * Fixed TNT lockup problems! Wheeeee!
410 * 83 6/01/99 3:52p Dave
411 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
412 * dead popup, pxo find player popup, pxo private room popup.
414 * 82 5/26/99 1:28p Jasenw
415 * changed coords for loading ani
417 * 81 5/26/99 11:46a Dave
418 * Added ship-blasting lighting and made the randomization of lighting
419 * much more customizable.
421 * 80 5/24/99 5:45p Dave
422 * Added detail levels to the nebula, with a decent speedup. Split nebula
423 * lightning into its own section.
441 #include "systemvars.h"
446 #include "starfield.h"
447 #include "lighting.h"
452 #include "fireballs.h"
456 #include "floating.h"
457 #include "gamesequence.h"
459 #include "optionsmenu.h"
460 #include "playermenu.h"
461 #include "trainingmenu.h"
462 #include "techmenu.h"
465 #include "hudmessage.h"
467 #include "missiongoals.h"
468 #include "missionparse.h"
473 #include "multiutil.h"
474 #include "multimsgs.h"
478 #include "freespace.h"
479 #include "managepilot.h"
481 #include "contexthelp.h"
484 #include "missionbrief.h"
485 #include "missiondebrief.h"
487 #include "missionshipchoice.h"
489 #include "hudconfig.h"
490 #include "controlsconfig.h"
491 #include "missionmessage.h"
492 #include "missiontraining.h"
494 #include "hudtarget.h"
498 #include "eventmusic.h"
499 #include "animplay.h"
500 #include "missionweaponchoice.h"
501 #include "missionlog.h"
502 #include "audiostr.h"
504 #include "missioncampaign.h"
506 #include "missionhotkey.h"
507 #include "objectsnd.h"
508 #include "cmeasure.h"
510 #include "linklist.h"
511 #include "shockwave.h"
512 #include "afterburner.h"
517 #include "stand_gui.h"
518 #include "pcxutils.h"
519 #include "hudtargetbox.h"
520 #include "multi_xfer.h"
521 #include "hudescort.h"
522 #include "multiutil.h"
525 #include "multiteamselect.h"
528 #include "readyroom.h"
529 #include "mainhallmenu.h"
530 #include "multilag.h"
532 #include "particle.h"
534 #include "multi_ingame.h"
535 #include "snazzyui.h"
536 #include "asteroid.h"
537 #include "popupdead.h"
538 #include "multi_voice.h"
539 #include "missioncmdbrief.h"
540 #include "redalert.h"
541 #include "gameplayhelp.h"
542 #include "multilag.h"
543 #include "staticrand.h"
544 #include "multi_pmsg.h"
545 #include "levelpaging.h"
546 #include "observer.h"
547 #include "multi_pause.h"
548 #include "multi_endgame.h"
549 #include "cutscenes.h"
550 #include "multi_respawn.h"
551 // #include "movie.h"
552 #include "multi_obj.h"
553 #include "multi_log.h"
555 #include "localize.h"
556 #include "osregistry.h"
557 #include "barracks.h"
558 #include "missionpause.h"
560 #include "alphacolors.h"
561 #include "objcollide.h"
564 #include "neblightning.h"
565 #include "shipcontrails.h"
568 #include "multi_dogfight.h"
569 #include "multi_rate.h"
570 #include "muzzleflash.h"
574 #include "mainhalltemp.h"
575 #include "exceptionhandler.h"
579 #include "supernova.h"
580 #include "hudshield.h"
581 // #include "names.h"
583 #include "missionloopbrief.h"
587 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
593 // 1.00.04 5/26/98 MWA -- going final (12 pm)
594 // 1.00.03 5/26/98 MWA -- going final (3 am)
595 // 1.00.02 5/25/98 MWA -- going final
596 // 1.00.01 5/25/98 MWA -- going final
597 // 0.90 5/21/98 MWA -- getting ready for final.
598 // 0.10 4/9/98. Set by MK.
600 // Demo version: (obsolete since DEMO codebase split from tree)
601 // 0.03 4/10/98 AL. Interplay rev
602 // 0.02 4/8/98 MK. Increased when this system was modified.
603 // 0.01 4/7/98? AL. First release to Interplay QA.
606 // 1.00 5/28/98 AL. First release to Interplay QA.
608 void game_level_init(int seed = -1);
609 void game_post_level_init();
610 void game_do_frame();
611 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
612 void game_reset_time();
613 void game_show_framerate(); // draws framerate in lower right corner
615 int Game_no_clear = 0;
617 int Pofview_running = 0;
618 int Nebedit_running = 0;
620 typedef struct big_expl_flash {
621 float max_flash_intensity; // max intensity
622 float cur_flash_intensity; // cur intensity
623 int flash_start; // start time
626 #define FRAME_FILTER 16
628 #define DEFAULT_SKILL_LEVEL 1
629 int Game_skill_level = DEFAULT_SKILL_LEVEL;
631 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
632 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
634 #define EXE_FNAME ("fs2.exe")
635 #define LAUNCHER_FNAME ("freespace2.exe")
637 // JAS: Code for warphole camera.
638 // Needs to be cleaned up.
639 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
640 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
641 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
642 matrix Camera_orient = IDENTITY_MATRIX;
643 float Camera_damping = 1.0f;
644 float Camera_time = 0.0f;
645 float Warpout_time = 0.0f;
646 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
647 int Warpout_sound = -1;
649 int Use_joy_mouse = 0;
650 int Use_palette_flash = 1;
652 int Use_fullscreen_at_startup = 0;
654 int Show_area_effect = 0;
655 object *Last_view_target = NULL;
657 int dogfight_blown = 0;
660 float frametimes[FRAME_FILTER];
661 float frametotal = 0.0f;
665 int Show_framerate = 0;
667 int Show_framerate = 1;
670 int Framerate_cap = 120;
673 int Show_target_debug_info = 0;
674 int Show_target_weapons = 0;
676 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
678 int Debug_octant = -1;
680 fix Game_time_compression = F1_0;
682 // if the ships.tbl the player has is valid
683 int Game_ships_tbl_valid = 0;
685 // if the weapons.tbl the player has is valid
686 int Game_weapons_tbl_valid = 0;
690 extern int Player_attacking_enabled;
694 int Pre_player_entry;
696 int Fred_running = 0;
697 char Game_current_mission_filename[MAX_FILENAME_LEN];
698 int game_single_step = 0;
699 int last_single_step=0;
701 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
702 extern int MSG_WINDOW_Y_START;
703 extern int MSG_WINDOW_HEIGHT;
705 int game_zbuffer = 1;
706 //static int Game_music_paused;
707 static int Game_paused;
711 #define EXPIRE_BAD_CHECKSUM 1
712 #define EXPIRE_BAD_TIME 2
714 extern void ssm_init();
715 extern void ssm_level_init();
716 extern void ssm_process();
718 // static variable to contain the time this version was built
719 // commented out for now until
720 // I figure out how to get the username into the file
721 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
723 // defines and variables used for dumping frame for making trailers.
725 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
726 int Debug_dump_trigger = 0;
727 int Debug_dump_frame_count;
728 int Debug_dump_frame_num = 0;
729 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
732 // amount of time to wait after the player has died before we display the death died popup
733 #define PLAYER_DIED_POPUP_WAIT 2500
734 int Player_died_popup_wait = -1;
735 int Player_multi_died_check = -1;
737 // builtin mission list stuff
739 int Game_builtin_mission_count = 6;
740 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
741 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
742 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
743 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
744 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
745 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
746 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
748 #elif defined(PD_BUILD)
749 int Game_builtin_mission_count = 4;
750 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
751 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
752 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
753 { "sm1-01", (FSB_FROM_VOLITION), "" },
754 { "sm1-05", (FSB_FROM_VOLITION), "" },
756 #elif defined(MULTIPLAYER_BETA)
757 int Game_builtin_mission_count = 17;
758 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
760 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
761 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
762 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
763 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
764 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
765 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
766 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
767 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
768 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
769 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
770 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
771 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
772 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
773 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
774 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
775 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
776 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
778 #elif defined(OEM_BUILD)
779 int Game_builtin_mission_count = 17;
780 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
781 // oem version - act 1 only
782 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
785 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
786 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
787 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
788 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
789 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
790 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
791 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
792 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
793 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
794 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
795 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
796 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
797 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
798 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
799 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
800 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
803 int Game_builtin_mission_count = 92;
804 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
805 // single player campaign
806 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
809 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
810 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
811 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
812 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
813 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
814 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
815 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
816 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
817 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
818 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
819 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
820 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
822 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
823 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
825 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
826 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
827 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
830 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
831 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
832 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
833 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
834 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
835 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
836 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
837 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
838 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
839 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
847 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
848 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
850 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
851 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
853 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
855 // multiplayer missions
858 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
859 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
864 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
865 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
906 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
907 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
911 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
912 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
913 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
914 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
915 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
920 // Internal function prototypes
921 void game_maybe_draw_mouse(float frametime);
922 void init_animating_pointer();
923 void load_animating_pointer(char *filename, int dx, int dy);
924 void unload_animating_pointer();
925 void game_do_training_checks();
926 void game_shutdown(void);
927 void game_show_event_debug(float frametime);
928 void game_event_debug_init();
930 void demo_upsell_show_screens();
931 void game_start_subspace_ambient_sound();
932 void game_stop_subspace_ambient_sound();
933 void verify_ships_tbl();
934 void verify_weapons_tbl();
935 void display_title_screen();
937 // loading background filenames
938 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
939 "LoadingBG", // GR_640
940 "2_LoadingBG" // GR_1024
944 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
945 "Loading.ani", // GR_640
946 "2_Loading.ani" // GR_1024
949 #if defined(FS2_DEMO)
950 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
954 #elif defined(OEM_BUILD)
955 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
962 char Game_CDROM_dir[MAX_PATH_LEN];
965 // How much RAM is on this machine. Set in WinMain
966 uint Freespace_total_ram = 0;
969 float Game_flash_red = 0.0f;
970 float Game_flash_green = 0.0f;
971 float Game_flash_blue = 0.0f;
972 float Sun_spot = 0.0f;
973 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
975 // game shudder stuff (in ms)
976 int Game_shudder_time = -1;
977 int Game_shudder_total = 0;
978 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
981 sound_env Game_sound_env;
982 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
983 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
985 int Game_sound_env_update_timestamp;
987 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
990 // WARPIN CRAP END --------------------------------------------------------------------------------------------
992 fs_builtin_mission *game_find_builtin_mission(char *filename)
996 // look through all existing builtin missions
997 for(idx=0; idx<Game_builtin_mission_count; idx++){
998 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
999 return &Game_builtin_mission_list[idx];
1007 int game_get_default_skill_level()
1009 return DEFAULT_SKILL_LEVEL;
1013 void game_flash_reset()
1015 Game_flash_red = 0.0f;
1016 Game_flash_green = 0.0f;
1017 Game_flash_blue = 0.0f;
1019 Big_expl_flash.max_flash_intensity = 0.0f;
1020 Big_expl_flash.cur_flash_intensity = 0.0f;
1021 Big_expl_flash.flash_start = 0;
1024 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1025 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1027 void game_framerate_check_init()
1029 // zero critical time
1030 Gf_critical_time = 0.0f;
1033 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1034 // if this is a glide card
1035 if(gr_screen.mode == GR_GLIDE){
1037 extern GrHwConfiguration hwconfig;
1040 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1041 Gf_critical = 15.0f;
1045 Gf_critical = 10.0f;
1050 Gf_critical = 15.0f;
1053 // d3d. only care about good cards here I guess (TNT)
1055 Gf_critical = 15.0f;
1058 // if this is a glide card
1059 if(gr_screen.mode == GR_GLIDE){
1061 extern GrHwConfiguration hwconfig;
1064 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1065 Gf_critical = 25.0f;
1069 Gf_critical = 20.0f;
1074 Gf_critical = 25.0f;
1077 // d3d. only care about good cards here I guess (TNT)
1079 Gf_critical = 25.0f;
1084 extern float Framerate;
1085 void game_framerate_check()
1089 // if the current framerate is above the critical level, add frametime
1090 if(Framerate >= Gf_critical){
1091 Gf_critical_time += flFrametime;
1094 if(!Show_framerate){
1098 // display if we're above the critical framerate
1099 if(Framerate < Gf_critical){
1100 gr_set_color_fast(&Color_bright_red);
1101 gr_string(200, y_start, "Framerate warning");
1106 // display our current pct of good frametime
1107 if(f2fl(Missiontime) >= 0.0f){
1108 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1111 gr_set_color_fast(&Color_bright_green);
1113 gr_set_color_fast(&Color_bright_red);
1116 gr_printf(200, y_start, "%d%%", (int)pct);
1123 // Adds a flash effect. These can be positive or negative.
1124 // The range will get capped at around -1 to 1, so stick
1125 // with a range like that.
1126 void game_flash( float r, float g, float b )
1128 Game_flash_red += r;
1129 Game_flash_green += g;
1130 Game_flash_blue += b;
1132 if ( Game_flash_red < -1.0f ) {
1133 Game_flash_red = -1.0f;
1134 } else if ( Game_flash_red > 1.0f ) {
1135 Game_flash_red = 1.0f;
1138 if ( Game_flash_green < -1.0f ) {
1139 Game_flash_green = -1.0f;
1140 } else if ( Game_flash_green > 1.0f ) {
1141 Game_flash_green = 1.0f;
1144 if ( Game_flash_blue < -1.0f ) {
1145 Game_flash_blue = -1.0f;
1146 } else if ( Game_flash_blue > 1.0f ) {
1147 Game_flash_blue = 1.0f;
1152 // Adds a flash for Big Ship explosions
1153 // cap range from 0 to 1
1154 void big_explosion_flash(float flash)
1156 Big_expl_flash.flash_start = timestamp(1);
1160 } else if (flash < 0.0f) {
1164 Big_expl_flash.max_flash_intensity = flash;
1165 Big_expl_flash.cur_flash_intensity = 0.0f;
1168 // Amount to diminish palette towards normal, per second.
1169 #define DIMINISH_RATE 0.75f
1170 #define SUN_DIMINISH_RATE 6.00f
1174 float sn_glare_scale = 1.7f;
1177 dc_get_arg(ARG_FLOAT);
1178 sn_glare_scale = Dc_arg_float;
1181 float Supernova_last_glare = 0.0f;
1182 void game_sunspot_process(float frametime)
1186 float Sun_spot_goal = 0.0f;
1189 sn_stage = supernova_active();
1191 // sunspot differently based on supernova stage
1193 // approaching. player still in control
1196 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1199 light_get_global_dir(&light_dir, 0);
1201 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1204 // scale it some more
1205 dot = dot * (0.5f + (pct * 0.5f));
1208 Sun_spot_goal += (dot * sn_glare_scale);
1211 // draw the sun glow
1212 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1213 // draw the glow for this sun
1214 stars_draw_sun_glow(0);
1217 Supernova_last_glare = Sun_spot_goal;
1220 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1223 Sun_spot_goal = 0.9f;
1224 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1226 if(Sun_spot_goal > 1.0f){
1227 Sun_spot_goal = 1.0f;
1230 Sun_spot_goal *= sn_glare_scale;
1231 Supernova_last_glare = Sun_spot_goal;
1234 // fade to white. display dead popup
1237 Supernova_last_glare += (2.0f * flFrametime);
1238 if(Supernova_last_glare > 2.0f){
1239 Supernova_last_glare = 2.0f;
1242 Sun_spot_goal = Supernova_last_glare;
1249 // check sunspots for all suns
1250 n_lights = light_get_global_count();
1253 for(idx=0; idx<n_lights; idx++){
1254 //(vector *eye_pos, matrix *eye_orient)
1255 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1258 light_get_global_dir(&light_dir, idx);
1260 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1262 Sun_spot_goal += (float)pow(dot,85.0f);
1264 // draw the glow for this sun
1265 stars_draw_sun_glow(idx);
1267 Sun_spot_goal = 0.0f;
1273 Sun_spot_goal = 0.0f;
1277 float dec_amount = frametime*SUN_DIMINISH_RATE;
1279 if ( Sun_spot < Sun_spot_goal ) {
1280 Sun_spot += dec_amount;
1281 if ( Sun_spot > Sun_spot_goal ) {
1282 Sun_spot = Sun_spot_goal;
1284 } else if ( Sun_spot > Sun_spot_goal ) {
1285 Sun_spot -= dec_amount;
1286 if ( Sun_spot < Sun_spot_goal ) {
1287 Sun_spot = Sun_spot_goal;
1293 // Call once a frame to diminish the
1294 // flash effect to 0.
1295 void game_flash_diminish(float frametime)
1297 float dec_amount = frametime*DIMINISH_RATE;
1299 if ( Game_flash_red > 0.0f ) {
1300 Game_flash_red -= dec_amount;
1301 if ( Game_flash_red < 0.0f )
1302 Game_flash_red = 0.0f;
1304 Game_flash_red += dec_amount;
1305 if ( Game_flash_red > 0.0f )
1306 Game_flash_red = 0.0f;
1309 if ( Game_flash_green > 0.0f ) {
1310 Game_flash_green -= dec_amount;
1311 if ( Game_flash_green < 0.0f )
1312 Game_flash_green = 0.0f;
1314 Game_flash_green += dec_amount;
1315 if ( Game_flash_green > 0.0f )
1316 Game_flash_green = 0.0f;
1319 if ( Game_flash_blue > 0.0f ) {
1320 Game_flash_blue -= dec_amount;
1321 if ( Game_flash_blue < 0.0f )
1322 Game_flash_blue = 0.0f;
1324 Game_flash_blue += dec_amount;
1325 if ( Game_flash_blue > 0.0f )
1326 Game_flash_blue = 0.0f;
1329 // update big_explosion_cur_flash
1330 #define TIME_UP 1500
1331 #define TIME_DOWN 2500
1332 int duration = TIME_UP + TIME_DOWN;
1333 int time = timestamp_until(Big_expl_flash.flash_start);
1334 if (time > -duration) {
1336 if (time < TIME_UP) {
1337 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1340 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1344 if ( Use_palette_flash ) {
1346 // static int or=0, og=0, ob=0;
1348 // Change the 200 to change the color range of colors.
1349 r = fl2i( Game_flash_red*128.0f );
1350 g = fl2i( Game_flash_green*128.0f );
1351 b = fl2i( Game_flash_blue*128.0f );
1353 if ( Sun_spot > 0.0f ) {
1354 r += fl2i(Sun_spot*128.0f);
1355 g += fl2i(Sun_spot*128.0f);
1356 b += fl2i(Sun_spot*128.0f);
1359 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1360 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1361 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1362 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1365 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1366 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1367 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1369 if ( (r!=0) || (g!=0) || (b!=0) ) {
1370 gr_flash( r, g, b );
1372 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1383 void game_level_close()
1385 // De-Initialize the game subsystems
1386 message_mission_shutdown();
1387 event_music_level_close();
1388 game_stop_looped_sounds();
1390 obj_snd_level_close(); // uninit object-linked persistant sounds
1391 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1392 anim_level_close(); // stop and clean up any anim instances
1393 shockwave_level_close();
1394 fireball_level_close();
1396 mission_event_shutdown();
1397 asteroid_level_close();
1398 model_cache_reset(); // Reset/free all the model caching stuff
1399 flak_level_close(); // unload flak stuff
1400 neb2_level_close(); // shutdown gaseous nebula stuff
1403 mflash_level_close();
1405 audiostream_unpause_all();
1410 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1411 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1412 void game_level_init(int seed)
1414 // seed the random number generator
1416 // if no seed was passed, seed the generator either from the time value, or from the
1417 // netgame security flags -- ensures that all players in multiplayer game will have the
1418 // same randon number sequence (with static rand functions)
1419 if ( Game_mode & GM_NORMAL ) {
1420 Game_level_seed = time(NULL);
1422 Game_level_seed = Netgame.security;
1425 // mwa 9/17/98 -- maybe this assert isn't needed????
1426 Assert( !(Game_mode & GM_MULTIPLAYER) );
1427 Game_level_seed = seed;
1429 srand( Game_level_seed );
1431 // semirand function needs to get re-initted every time in multiplayer
1432 if ( Game_mode & GM_MULTIPLAYER ){
1438 Key_normal_game = (Game_mode & GM_NORMAL);
1441 Game_shudder_time = -1;
1443 // Initialize the game subsystems
1444 // timestamp_reset(); // Must be inited before everything else
1446 game_reset_time(); // resets time, and resets saved time too
1448 obj_init(); // Must be inited before the other systems
1449 model_free_all(); // Free all existing models
1450 mission_brief_common_init(); // Free all existing briefing/debriefing text
1451 weapon_level_init();
1452 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1454 player_level_init();
1455 shipfx_flash_init(); // Init the ship gun flash system.
1456 game_flash_reset(); // Reset the flash effect
1457 particle_init(); // Reset the particle system
1461 shield_hit_init(); // Initialize system for showing shield hits
1462 radar_mission_init();
1463 mission_init_goals();
1466 obj_snd_level_init(); // init object-linked persistant sounds
1468 shockwave_level_init();
1469 afterburner_level_init();
1470 scoring_level_init( &Player->stats );
1472 asteroid_level_init();
1473 control_config_clear_used_status();
1474 collide_ship_ship_sounds_init();
1476 Pre_player_entry = 1; // Means the player has not yet entered.
1477 Entry_delay_time = 0; // Could get overwritten in mission read.
1478 fireball_preload(); // page in warphole bitmaps
1480 flak_level_init(); // initialize flak - bitmaps, etc
1481 ct_level_init(); // initialize ships contrails, etc
1482 awacs_level_init(); // initialize AWACS
1483 beam_level_init(); // initialize beam weapons
1484 mflash_level_init();
1486 supernova_level_init();
1488 // multiplayer dogfight hack
1491 shipfx_engine_wash_level_init();
1495 Last_view_target = NULL;
1500 // campaign wasn't ended
1501 Campaign_ended_in_mission = 0;
1504 // called when a mission is over -- does server specific stuff.
1505 void freespace_stop_mission()
1508 Game_mode &= ~GM_IN_MISSION;
1511 // called at frame interval to process networking stuff
1512 void game_do_networking()
1514 Assert( Net_player != NULL );
1515 if (!(Game_mode & GM_MULTIPLAYER)){
1519 // see if this player should be reading/writing data. Bit is set when at join
1520 // screen onward until quits back to main menu.
1521 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1525 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1528 multi_pause_do_frame();
1533 // Loads the best palette for this level, based
1534 // on nebula color and hud color. You could just call palette_load_table with
1535 // the appropriate filename, but who wants to do that.
1536 void game_load_palette()
1538 char palette_filename[1024];
1540 // We only use 3 hud colors right now
1541 // Assert( HUD_config.color >= 0 );
1542 // Assert( HUD_config.color <= 2 );
1544 Assert( Mission_palette >= 0 );
1545 Assert( Mission_palette <= 98 );
1547 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1548 strcpy( palette_filename, NOX("gamepalette-subspace") );
1550 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1553 mprintf(( "Loading palette %s\n", palette_filename ));
1555 // palette_load_table(palette_filename);
1558 void game_post_level_init()
1560 // Stuff which gets called after mission is loaded. Because player isn't created until
1561 // after mission loads, some things must get initted after the level loads
1563 model_level_post_init();
1566 hud_setup_escort_list();
1567 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1573 game_event_debug_init();
1576 training_mission_init();
1577 asteroid_create_all();
1579 game_framerate_check_init();
1583 // An estimate as to how high the count passed to game_loading_callback will go.
1584 // This is just a guess, it seems to always be about the same. The count is
1585 // proportional to the code being executed, not the time, so this works good
1586 // for a bar, assuming the code does about the same thing each time you
1587 // load a level. You can find this value by looking at the return value
1588 // of game_busy_callback(NULL), which I conveniently print out to the
1589 // debug output window with the '=== ENDING LOAD ==' stuff.
1590 //#define COUNT_ESTIMATE 3706
1591 #define COUNT_ESTIMATE 1111
1593 int Game_loading_callback_inited = 0;
1595 int Game_loading_background = -1;
1596 anim * Game_loading_ani = NULL;
1597 anim_instance *Game_loading_ani_instance;
1598 int Game_loading_frame=-1;
1600 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1609 // This gets called 10x per second and count is the number of times
1610 // game_busy() has been called since the current callback function
1612 void game_loading_callback(int count)
1614 game_do_networking();
1616 Assert( Game_loading_callback_inited==1 );
1617 Assert( Game_loading_ani != NULL );
1619 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1620 if ( framenum > Game_loading_ani->total_frames-1 ) {
1621 framenum = Game_loading_ani->total_frames-1;
1622 } else if ( framenum < 0 ) {
1627 while ( Game_loading_frame < framenum ) {
1628 Game_loading_frame++;
1629 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1633 if ( cbitmap > -1 ) {
1634 if ( Game_loading_background > -1 ) {
1635 gr_set_bitmap( Game_loading_background );
1639 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1640 gr_set_bitmap( cbitmap );
1641 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1643 bm_release(cbitmap);
1649 void game_loading_callback_init()
1651 Assert( Game_loading_callback_inited==0 );
1653 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1654 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1657 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1658 Assert( Game_loading_ani != NULL );
1659 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1660 Assert( Game_loading_ani_instance != NULL );
1661 Game_loading_frame = -1;
1663 Game_loading_callback_inited = 1;
1665 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1670 void game_loading_callback_close()
1672 Assert( Game_loading_callback_inited==1 );
1674 // Make sure bar shows all the way over.
1675 game_loading_callback(COUNT_ESTIMATE);
1677 int real_count = game_busy_callback( NULL );
1680 Game_loading_callback_inited = 0;
1683 mprintf(( "=================== ENDING LOAD ================\n" ));
1684 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1685 mprintf(( "================================================\n" ));
1687 // to remove warnings in release build
1691 free_anim_instance(Game_loading_ani_instance);
1692 Game_loading_ani_instance = NULL;
1693 anim_free(Game_loading_ani);
1694 Game_loading_ani = NULL;
1696 bm_release( Game_loading_background );
1697 common_free_interface_palette(); // restore game palette
1698 Game_loading_background = -1;
1700 gr_set_font( FONT1 );
1703 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1705 void game_maybe_update_sound_environment()
1707 // do nothing for now
1710 // Assign the sound environment for the game, based on the current mission
1712 void game_assign_sound_environment()
1715 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1716 Game_sound_env.id = SND_ENV_DRUGGED;
1717 Game_sound_env.volume = 0.800f;
1718 Game_sound_env.damping = 1.188f;
1719 Game_sound_env.decay = 6.392f;
1721 } else if (Num_asteroids > 30) {
1722 Game_sound_env.id = SND_ENV_AUDITORIUM;
1723 Game_sound_env.volume = 0.603f;
1724 Game_sound_env.damping = 0.5f;
1725 Game_sound_env.decay = 4.279f;
1728 Game_sound_env = Game_default_sound_env;
1732 Game_sound_env = Game_default_sound_env;
1733 Game_sound_env_update_timestamp = timestamp(1);
1736 // function which gets called before actually entering the mission. It is broken down into a funciton
1737 // since it will get called in one place from a single player game and from another place for
1738 // a multiplayer game
1739 void freespace_mission_load_stuff()
1741 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1742 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1743 if(!(Game_mode & GM_STANDALONE_SERVER)){
1745 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1747 game_loading_callback_init();
1749 event_music_level_init(); // preloads the first 2 seconds for each event music track
1752 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1755 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1758 ship_assign_sound_all(); // assign engine sounds to ships
1759 game_assign_sound_environment(); // assign the sound environment for this mission
1762 // call function in missionparse.cpp to fixup player/ai stuff.
1763 mission_parse_fixup_players();
1766 // Load in all the bitmaps for this level
1771 game_loading_callback_close();
1773 // the only thing we need to call on the standalone for now.
1775 // call function in missionparse.cpp to fixup player/ai stuff.
1776 mission_parse_fixup_players();
1778 // Load in all the bitmaps for this level
1784 uint load_mission_load;
1785 uint load_post_level_init;
1786 uint load_mission_stuff;
1788 // tells the server to load the mission and initialize structures
1789 int game_start_mission()
1791 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1793 load_gl_init = time(NULL);
1795 load_gl_init = time(NULL) - load_gl_init;
1797 if (Game_mode & GM_MULTIPLAYER) {
1798 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1800 // clear multiplayer stats
1801 init_multiplayer_stats();
1804 load_mission_load = time(NULL);
1805 if (mission_load()) {
1806 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1807 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1808 gameseq_post_event(GS_EVENT_MAIN_MENU);
1810 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1815 load_mission_load = time(NULL) - load_mission_load;
1817 // If this is a red alert mission in campaign mode, bash wingman status
1818 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1819 red_alert_bash_wingman_status();
1822 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1823 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1824 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1825 // game_load_palette();
1828 load_post_level_init = time(NULL);
1829 game_post_level_init();
1830 load_post_level_init = time(NULL) - load_post_level_init;
1834 void Do_model_timings_test();
1835 Do_model_timings_test();
1839 load_mission_stuff = time(NULL);
1840 freespace_mission_load_stuff();
1841 load_mission_stuff = time(NULL) - load_mission_stuff;
1846 int Interface_framerate = 0;
1849 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1850 DCF_BOOL( show_framerate, Show_framerate )
1851 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1852 DCF_BOOL( show_target_weapons, Show_target_weapons )
1853 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1854 DCF_BOOL( sound, Sound_enabled )
1855 DCF_BOOL( zbuffer, game_zbuffer )
1856 DCF_BOOL( shield_system, New_shield_system )
1857 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1858 DCF_BOOL( player_attacking, Player_attacking_enabled )
1859 DCF_BOOL( show_waypoints, Show_waypoints )
1860 DCF_BOOL( show_area_effect, Show_area_effect )
1861 DCF_BOOL( show_net_stats, Show_net_stats )
1862 DCF_BOOL( log, Log_debug_output_to_file )
1863 DCF_BOOL( training_msg_method, Training_msg_method )
1864 DCF_BOOL( show_player_pos, Show_player_pos )
1865 DCF_BOOL(i_framerate, Interface_framerate )
1867 DCF(show_mem,"Toggles showing mem usage")
1870 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1871 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1872 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1873 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1879 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1881 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1882 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1886 DCF(show_cpu,"Toggles showing cpu usage")
1889 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1890 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1891 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1892 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1898 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1900 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1901 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1908 // AL 4-8-98: always allow players to display their framerate
1911 DCF_BOOL( show_framerate, Show_framerate )
1918 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1921 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1922 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1923 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1924 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1926 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" );
1927 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1929 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1932 DCF(palette_flash,"Toggles palette flash effect on/off")
1935 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1936 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1937 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1938 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1940 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1941 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1944 int Use_low_mem = 0;
1946 DCF(low_mem,"Uses low memory settings regardless of RAM")
1949 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1950 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1951 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1952 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1954 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1955 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1957 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1963 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1966 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1967 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1968 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1969 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1971 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1972 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1973 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1977 int Framerate_delay = 0;
1979 float Freespace_gamma = 1.0f;
1981 DCF(gamma,"Sets Gamma factor")
1984 dc_get_arg(ARG_FLOAT|ARG_NONE);
1985 if ( Dc_arg_type & ARG_FLOAT ) {
1986 Freespace_gamma = Dc_arg_float;
1988 dc_printf( "Gamma reset to 1.0f\n" );
1989 Freespace_gamma = 1.0f;
1991 if ( Freespace_gamma < 0.1f ) {
1992 Freespace_gamma = 0.1f;
1993 } else if ( Freespace_gamma > 5.0f ) {
1994 Freespace_gamma = 5.0f;
1996 gr_set_gamma(Freespace_gamma);
1998 char tmp_gamma_string[32];
1999 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2000 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2004 dc_printf( "Usage: gamma <float>\n" );
2005 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2006 Dc_status = 0; // don't print status if help is printed. Too messy.
2010 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2019 Game_current_mission_filename[0] = 0;
2021 // seed the random number generator
2022 Game_init_seed = time(NULL);
2023 srand( Game_init_seed );
2025 Framerate_delay = 0;
2031 extern void bm_init();
2037 // Initialize the timer before the os
2045 GetCurrentDirectory(1024, whee);
2048 getcwd (whee, 1024);
2051 strcat(whee, EXE_FNAME);
2053 //Initialize the libraries
2054 s1 = timer_get_milliseconds();
2055 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2058 e1 = timer_get_milliseconds();
2060 // time a bunch of cfopens
2062 s2 = timer_get_milliseconds();
2064 for(int idx=0; idx<10000; idx++){
2065 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2070 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2072 e2 = timer_get_milliseconds();
2075 if (Is_standalone) {
2076 std_init_standalone();
2078 os_init( Osreg_class_name, Osreg_app_name );
2079 os_set_title(Osreg_title);
2082 // initialize localization module. Make sure this is down AFTER initialzing OS.
2083 // int t1 = timer_get_milliseconds();
2086 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2088 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2091 // verify that he has a valid weapons.tbl
2092 verify_weapons_tbl();
2094 // Output version numbers to registry for auto patching purposes
2095 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2096 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2097 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2099 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2100 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2101 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2104 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2108 Asteroids_enabled = 1;
2111 /////////////////////////////
2113 /////////////////////////////
2118 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2119 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2121 if (!stricmp(ptr, NOX("no sound"))) {
2122 Cmdline_freespace_no_sound = 1;
2124 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2126 } else if (!stricmp(ptr, NOX("EAX"))) {
2131 if (!Is_standalone) {
2132 snd_init(use_a3d, use_eax);
2134 /////////////////////////////
2136 /////////////////////////////
2138 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2141 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);
2143 // fire up the UpdateLauncher executable
2145 PROCESS_INFORMATION pi;
2147 memset( &si, 0, sizeof(STARTUPINFO) );
2150 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2151 NULL, // pointer to command line string
2152 NULL, // pointer to process security attributes
2153 NULL, // pointer to thread security attributes
2154 FALSE, // handle inheritance flag
2155 CREATE_DEFAULT_ERROR_MODE, // creation flags
2156 NULL, // pointer to new environment block
2157 NULL, // pointer to current directory name
2158 &si, // pointer to STARTUPINFO
2159 &pi // pointer to PROCESS_INFORMATION
2162 // If the Launcher could not be started up, let the user know
2164 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2173 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2175 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);
2183 // check for hi res pack file
2184 int has_sparky_hi = 0;
2186 // check if sparky_hi exists -- access mode 0 means does file exist
2189 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2192 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2195 // see if we've got 32 bit in the string
2196 if(strstr(ptr, "32 bit")){
2202 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2204 // always 640 for E3
2205 gr_init(GR_640, GR_GLIDE);
2207 // regular or hi-res ?
2209 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2211 if(strstr(ptr, NOX("(1024x768)"))){
2213 gr_init(GR_1024, GR_GLIDE);
2215 gr_init(GR_640, GR_GLIDE);
2218 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2220 // always 640 for E3
2222 gr_init(GR_640, GR_DIRECT3D, depth);
2224 // regular or hi-res ?
2226 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2228 if(strstr(ptr, NOX("(1024x768)"))){
2232 gr_init(GR_1024, GR_DIRECT3D, depth);
2236 gr_init(GR_640, GR_DIRECT3D, depth);
2242 if ( Use_fullscreen_at_startup && !Is_standalone) {
2243 gr_init(GR_640, GR_DIRECTDRAW);
2245 gr_init(GR_640, GR_SOFTWARE);
2248 if ( !Is_standalone ) {
2249 gr_init(GR_640, GR_DIRECTDRAW);
2251 gr_init(GR_640, GR_SOFTWARE);
2257 extern int Gr_inited;
2258 if(trying_d3d && !Gr_inited){
2259 extern char Device_init_error[512];
2261 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2270 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2271 Freespace_gamma = (float)atof(ptr);
2272 if ( Freespace_gamma < 0.1f ) {
2273 Freespace_gamma = 0.1f;
2274 } else if ( Freespace_gamma > 5.0f ) {
2275 Freespace_gamma = 5.0f;
2277 char tmp_gamma_string[32];
2278 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2279 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2281 gr_set_gamma(Freespace_gamma);
2283 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2286 display_title_screen();
2290 // attempt to load up master tracker registry info (login and password)
2291 Multi_tracker_id = -1;
2293 // pxo login and password
2294 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2296 nprintf(("Network","Error reading in PXO login data\n"));
2297 strcpy(Multi_tracker_login,"");
2299 strcpy(Multi_tracker_login,ptr);
2301 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2303 nprintf(("Network","Error reading PXO password\n"));
2304 strcpy(Multi_tracker_passwd,"");
2306 strcpy(Multi_tracker_passwd,ptr);
2309 // pxo squad name and password
2310 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2312 nprintf(("Network","Error reading in PXO squad name\n"));
2313 strcpy(Multi_tracker_squad_name, "");
2315 strcpy(Multi_tracker_squad_name, ptr);
2318 // If less than 48MB of RAM, use low memory model.
2319 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2320 mprintf(( "Using normal memory settings...\n" ));
2321 bm_set_low_mem(1); // Use every other frame of bitmaps
2323 mprintf(( "Using high memory settings...\n" ));
2324 bm_set_low_mem(0); // Use all frames of bitmaps
2327 // load non-darkening pixel defs
2328 palman_load_pixels();
2330 // hud shield icon stuff
2331 hud_shield_game_init();
2333 control_config_common_init(); // sets up localization stuff in the control config
2339 gamesnd_parse_soundstbl();
2344 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2349 player_controls_init();
2352 //if(!Is_standalone){
2360 ship_init(); // read in ships.tbl
2362 mission_campaign_init(); // load in the default campaign
2364 // navmap_init(); // init the navigation map system
2365 context_help_init();
2366 techroom_intel_init(); // parse species.tbl, load intel info
2368 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2369 init_animating_pointer();
2371 mission_brief_common_init(); // Mark all the briefing structures as empty.
2372 gr_font_init(); // loads up all fonts
2374 neb2_init(); // fullneb stuff
2378 player_tips_init(); // helpful tips
2381 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2382 pilot_load_pic_list();
2383 pilot_load_squad_pic_list();
2385 load_animating_pointer(NOX("cursor"), 0, 0);
2387 // initialize alpha colors
2388 alpha_colors_init();
2391 // Game_music_paused = 0;
2398 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2399 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2401 mprintf(("cfile_init() took %d\n", e1 - s1));
2402 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2405 char transfer_text[128];
2407 float Start_time = 0.0f;
2409 float Framerate = 0.0f;
2411 float Timing_total = 0.0f;
2412 float Timing_render2 = 0.0f;
2413 float Timing_render3 = 0.0f;
2414 float Timing_flip = 0.0f;
2415 float Timing_clear = 0.0f;
2417 MONITOR(NumPolysDrawn);
2423 void game_get_framerate()
2425 char text[128] = "";
2427 if ( frame_int == -1 ) {
2429 for (i=0; i<FRAME_FILTER; i++ ) {
2430 frametimes[i] = 0.0f;
2435 frametotal -= frametimes[frame_int];
2436 frametotal += flFrametime;
2437 frametimes[frame_int] = flFrametime;
2438 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2440 if ( frametotal != 0.0 ) {
2441 if ( Framecount >= FRAME_FILTER )
2442 Framerate = FRAME_FILTER / frametotal;
2444 Framerate = Framecount / frametotal;
2445 sprintf( text, NOX("FPS: %.1f"), Framerate );
2447 sprintf( text, NOX("FPS: ?") );
2451 if (Show_framerate) {
2452 gr_set_color_fast(&HUD_color_debug);
2453 gr_string( 570, 2, text );
2457 void game_show_framerate()
2461 cur_time = f2fl(timer_get_approx_seconds());
2462 if (cur_time - Start_time > 30.0f) {
2463 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2464 Start_time += 1000.0f;
2467 //mprintf(( "%s\n", text ));
2470 if ( Debug_dump_frames )
2474 // possibly show control checking info
2475 control_check_indicate();
2477 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2478 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2479 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2480 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2483 if ( Show_cpu == 1 ) {
2488 dy = gr_get_font_height() + 1;
2490 gr_set_color_fast(&HUD_color_debug);
2494 extern int D3D_textures_in;
2495 extern int D3D_textures_in_frame;
2496 extern int Glide_textures_in;
2497 extern int Glide_textures_in_frame;
2498 extern int Glide_explosion_vram;
2499 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2501 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2503 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2509 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2511 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2513 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2515 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2517 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2522 extern int Num_pairs; // Number of object pairs that were checked.
2523 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2526 extern int Num_pairs_checked; // What percent of object pairs were checked.
2527 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2529 Num_pairs_checked = 0;
2533 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2536 if ( Timing_total > 0.01f ) {
2537 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2539 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2541 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2543 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2545 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2555 dy = gr_get_font_height() + 1;
2557 gr_set_color_fast(&HUD_color_debug);
2560 extern int TotalRam;
2561 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2566 extern int Model_ram;
2567 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2571 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2573 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2575 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2579 extern int D3D_textures_in;
2580 extern int Glide_textures_in;
2581 extern int Glide_textures_in_frame;
2582 extern int Glide_explosion_vram;
2583 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2585 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2587 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2596 if ( Show_player_pos ) {
2600 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));
2603 MONITOR_INC(NumPolys, modelstats_num_polys);
2604 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2605 MONITOR_INC(NumVerts, modelstats_num_verts );
2607 modelstats_num_polys = 0;
2608 modelstats_num_polys_drawn = 0;
2609 modelstats_num_verts = 0;
2610 modelstats_num_sortnorms = 0;
2614 void game_show_standalone_framerate()
2616 float frame_rate=30.0f;
2617 if ( frame_int == -1 ) {
2619 for (i=0; i<FRAME_FILTER; i++ ) {
2620 frametimes[i] = 0.0f;
2625 frametotal -= frametimes[frame_int];
2626 frametotal += flFrametime;
2627 frametimes[frame_int] = flFrametime;
2628 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2630 if ( frametotal != 0.0 ) {
2631 if ( Framecount >= FRAME_FILTER ){
2632 frame_rate = FRAME_FILTER / frametotal;
2634 frame_rate = Framecount / frametotal;
2637 std_set_standalone_fps(frame_rate);
2641 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2642 void game_show_time_left()
2646 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2647 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2648 // checking how much time is left
2650 if ( Mission_end_time == -1 ){
2654 diff = f2i(Mission_end_time - Missiontime);
2655 // be sure to bash to 0. diff could be negative on frame that we quit mission
2660 hud_set_default_color();
2661 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2664 //========================================================================================
2665 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2666 //========================================================================================
2670 DCF(ai_pause,"Pauses ai")
2673 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2674 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2675 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2676 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2679 obj_init_all_ships_physics();
2682 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2683 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2686 DCF(single_step,"Single steps the game")
2689 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2690 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2691 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2692 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2694 last_single_step = 0; // Make so single step waits a frame before stepping
2697 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2698 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2701 DCF_BOOL(physics_pause, physics_paused)
2702 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2703 DCF_BOOL(ai_firing, Ai_firing_enabled )
2705 // Create some simple aliases to these commands...
2706 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2707 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2708 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2709 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2710 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2713 //========================================================================================
2714 //========================================================================================
2717 void game_training_pause_do()
2721 key = game_check_key();
2723 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2730 void game_increase_skill_level()
2733 if (Game_skill_level >= NUM_SKILL_LEVELS){
2734 Game_skill_level = 0;
2738 int Player_died_time;
2740 int View_percent = 100;
2743 DCF(view, "Sets the percent of the 3d view to render.")
2746 dc_get_arg(ARG_INT);
2747 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2748 View_percent = Dc_arg_int;
2750 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2756 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2760 dc_printf("View is set to %d%%\n", View_percent );
2765 // Set the clip region for the 3d rendering window
2766 void game_set_view_clip()
2768 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2769 // Set the clip region for the letterbox "dead view"
2770 int yborder = gr_screen.max_h/4;
2772 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2773 // J.S. I've changed my ways!! See the new "no constants" code!!!
2774 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2776 // Set the clip region for normal view
2777 if ( View_percent >= 100 ) {
2780 int xborder, yborder;
2782 if ( View_percent < 5 ) {
2786 float fp = i2fl(View_percent)/100.0f;
2787 int fi = fl2i(fl_sqrt(fp)*100.0f);
2788 if ( fi > 100 ) fi=100;
2790 xborder = ( gr_screen.max_w*(100-fi) )/200;
2791 yborder = ( gr_screen.max_h*(100-fi) )/200;
2793 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2799 void show_debug_stuff()
2802 int laser_count = 0, missile_count = 0;
2804 for (i=0; i<MAX_OBJECTS; i++) {
2805 if (Objects[i].type == OBJ_WEAPON){
2806 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2808 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2814 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2817 extern int Tool_enabled;
2822 int tst_bitmap = -1;
2824 float tst_offset, tst_offset_total;
2827 void game_tst_frame_pre()
2835 g3_rotate_vertex(&v, &tst_pos);
2836 g3_project_vertex(&v);
2839 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2843 // big ship? always tst
2845 // within 3000 meters
2846 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2850 // within 300 meters
2851 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2858 void game_tst_frame()
2868 tst_time = time(NULL);
2870 // load the tst bitmap
2871 switch((int)frand_range(0.0f, 3.0)){
2873 tst_bitmap = bm_load("ig_jim");
2875 mprintf(("TST 0\n"));
2879 tst_bitmap = bm_load("ig_kan");
2881 mprintf(("TST 1\n"));
2885 tst_bitmap = bm_load("ig_jim");
2887 mprintf(("TST 2\n"));
2891 tst_bitmap = bm_load("ig_kan");
2893 mprintf(("TST 3\n"));
2902 // get the tst bitmap dimensions
2904 bm_get_info(tst_bitmap, &w, &h);
2907 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2909 snd_play(&Snds[SND_VASUDAN_BUP]);
2911 // tst x and direction
2915 tst_offset_total = (float)w;
2916 tst_offset = (float)w;
2918 tst_x = (float)gr_screen.max_w;
2919 tst_offset_total = (float)-w;
2920 tst_offset = (float)w;
2928 float diff = (tst_offset_total / 0.5f) * flFrametime;
2934 tst_offset -= fl_abs(diff);
2935 } else if(tst_mode == 2){
2938 tst_offset -= fl_abs(diff);
2942 gr_set_bitmap(tst_bitmap);
2943 gr_bitmap((int)tst_x, (int)tst_y);
2946 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2950 // if we passed the switch point
2951 if(tst_offset <= 0.0f){
2956 tst_stamp = timestamp(1000);
2957 tst_offset = fl_abs(tst_offset_total);
2968 void game_tst_mark(object *objp, ship *shipp)
2977 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2980 sip = &Ship_info[shipp->ship_info_index];
2987 tst_pos = objp->pos;
2988 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2994 extern void render_shields();
2996 void player_repair_frame(float frametime)
2998 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3000 for(idx=0;idx<MAX_PLAYERS;idx++){
3003 np = &Net_players[idx];
3005 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)){
3007 // don't rearm/repair if the player is dead or dying/departing
3008 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3009 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3014 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3015 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3021 #define NUM_FRAMES_TEST 300
3022 #define NUM_MIXED_SOUNDS 16
3023 void do_timing_test(float flFrametime)
3025 static int framecount = 0;
3026 static int test_running = 0;
3027 static float test_time = 0.0f;
3029 static int snds[NUM_MIXED_SOUNDS];
3032 if ( test_running ) {
3034 test_time += flFrametime;
3035 if ( framecount >= NUM_FRAMES_TEST ) {
3037 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3038 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3043 if ( Test_begin == 1 ) {
3049 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3052 // start looping digital sounds
3053 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3054 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3061 DCF(dcf_fov, "Change the field of view")
3064 dc_get_arg(ARG_FLOAT|ARG_NONE);
3065 if ( Dc_arg_type & ARG_NONE ) {
3066 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3067 dc_printf( "Zoom factor reset\n" );
3069 if ( Dc_arg_type & ARG_FLOAT ) {
3070 if (Dc_arg_float < 0.25f) {
3071 Viewer_zoom = 0.25f;
3072 dc_printf("Zoom factor pinned at 0.25.\n");
3073 } else if (Dc_arg_float > 1.25f) {
3074 Viewer_zoom = 1.25f;
3075 dc_printf("Zoom factor pinned at 1.25.\n");
3077 Viewer_zoom = Dc_arg_float;
3083 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3086 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3090 DCF(framerate_cap, "Sets the framerate cap")
3093 dc_get_arg(ARG_INT);
3094 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3095 Framerate_cap = Dc_arg_int;
3097 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3103 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3104 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3105 dc_printf("[n] must be from 1 to 120.\n");
3109 if ( Framerate_cap )
3110 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3112 dc_printf("There is no framerate cap currently active.\n");
3116 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3117 int Show_viewing_from_self = 0;
3119 void say_view_target()
3121 object *view_target;
3123 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3124 view_target = &Objects[Player_ai->target_objnum];
3126 view_target = Player_obj;
3128 if (Game_mode & GM_DEAD) {
3129 if (Player_ai->target_objnum != -1)
3130 view_target = &Objects[Player_ai->target_objnum];
3133 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3134 if (view_target != Player_obj){
3136 char *view_target_name = NULL;
3137 switch(Objects[Player_ai->target_objnum].type) {
3139 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3142 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3143 Viewer_mode &= ~VM_OTHER_SHIP;
3145 case OBJ_JUMP_NODE: {
3146 char jump_node_name[128];
3147 strcpy(jump_node_name, XSTR( "jump node", 184));
3148 view_target_name = jump_node_name;
3149 Viewer_mode &= ~VM_OTHER_SHIP;
3158 if ( view_target_name ) {
3159 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3160 Show_viewing_from_self = 1;
3163 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3164 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3165 Show_viewing_from_self = 1;
3167 if (Show_viewing_from_self)
3168 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3173 Last_view_target = view_target;
3177 float Game_hit_x = 0.0f;
3178 float Game_hit_y = 0.0f;
3180 // Reset at the beginning of each frame
3181 void game_whack_reset()
3187 // Apply a 2d whack to the player
3188 void game_whack_apply( float x, float y )
3190 // Do some force feedback
3191 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3197 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3200 // call to apply a "shudder"
3201 void game_shudder_apply(int time, float intensity)
3203 Game_shudder_time = timestamp(time);
3204 Game_shudder_total = time;
3205 Game_shudder_intensity = intensity;
3208 #define FF_SCALE 10000
3209 void apply_hud_shake(matrix *eye_orient)
3211 if (Viewer_obj == Player_obj) {
3212 physics_info *pi = &Player_obj->phys_info;
3220 // Make eye shake due to afterburner
3221 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3224 dtime = timestamp_until(pi->afterburner_decay);
3228 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3229 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3232 // Make eye shake due to engine wash
3234 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3237 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3238 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3240 // get the intensity
3241 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3245 vm_vec_rand_vec_quick(&rand_vec);
3248 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3252 // make hud shake due to shuddering
3253 if(Game_shudder_time != -1){
3254 // if the timestamp has elapsed
3255 if(timestamp_elapsed(Game_shudder_time)){
3256 Game_shudder_time = -1;
3258 // otherwise apply some shudder
3262 dtime = timestamp_until(Game_shudder_time);
3266 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));
3267 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));
3272 vm_angles_2_matrix(&tm, &tangles);
3273 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3274 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3275 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3276 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3281 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3283 // Player's velocity just before he blew up. Used to keep camera target moving.
3284 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3286 // Set eye_pos and eye_orient based on view mode.
3287 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3291 static int last_Viewer_mode = 0;
3292 static int last_Game_mode = 0;
3293 static int last_Viewer_objnum = -1;
3295 // This code is supposed to detect camera "cuts"... like going between
3298 // determine if we need to regenerate the nebula
3299 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3300 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3301 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3302 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3303 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3304 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3305 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3306 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3307 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3310 // regenerate the nebula
3314 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3315 //mprintf(( "************** Camera cut! ************\n" ));
3316 last_Viewer_mode = Viewer_mode;
3317 last_Game_mode = Game_mode;
3319 // Camera moved. Tell stars & debris to not do blurring.
3325 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3326 player_display_packlock_view();
3329 game_set_view_clip();
3331 if (Game_mode & GM_DEAD) {
3332 vector vec_to_deader, view_pos;
3335 Viewer_mode |= VM_DEAD_VIEW;
3337 if (Player_ai->target_objnum != -1) {
3338 int view_from_player = 1;
3340 if (Viewer_mode & VM_OTHER_SHIP) {
3341 // View from target.
3342 Viewer_obj = &Objects[Player_ai->target_objnum];
3344 last_Viewer_objnum = Player_ai->target_objnum;
3346 if ( Viewer_obj->type == OBJ_SHIP ) {
3347 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3348 view_from_player = 0;
3351 last_Viewer_objnum = -1;
3354 if ( view_from_player ) {
3355 // View target from player ship.
3357 *eye_pos = Player_obj->pos;
3358 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3359 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3362 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3364 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3365 dist += flFrametime * 16.0f;
3367 vm_vec_scale(&vec_to_deader, -dist);
3368 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3370 view_pos = Player_obj->pos;
3372 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3373 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3374 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3375 Dead_player_last_vel = Player_obj->phys_info.vel;
3376 //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));
3377 } else if (Player_ai->target_objnum != -1) {
3378 view_pos = Objects[Player_ai->target_objnum].pos;
3380 // Make camera follow explosion, but gradually slow down.
3381 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3382 view_pos = Player_obj->pos;
3383 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3384 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3387 *eye_pos = Dead_camera_pos;
3389 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3391 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3396 // if supernova shockwave
3397 if(supernova_camera_cut()){
3401 // call it dead view
3402 Viewer_mode |= VM_DEAD_VIEW;
3404 // set eye pos and orient
3405 supernova_set_view(eye_pos, eye_orient);
3407 // If already blown up, these other modes can override.
3408 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3409 Viewer_mode &= ~VM_DEAD_VIEW;
3411 Viewer_obj = Player_obj;
3413 if (Viewer_mode & VM_OTHER_SHIP) {
3414 if (Player_ai->target_objnum != -1){
3415 Viewer_obj = &Objects[Player_ai->target_objnum];
3416 last_Viewer_objnum = Player_ai->target_objnum;
3418 Viewer_mode &= ~VM_OTHER_SHIP;
3419 last_Viewer_objnum = -1;
3422 last_Viewer_objnum = -1;
3425 if (Viewer_mode & VM_EXTERNAL) {
3428 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3429 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3431 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3433 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3434 vm_vec_normalize(&eye_dir);
3435 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3438 // Modify the orientation based on head orientation.
3439 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3441 } else if ( Viewer_mode & VM_CHASE ) {
3444 if ( Viewer_obj->phys_info.speed < 0.1 )
3445 move_dir = Viewer_obj->orient.fvec;
3447 move_dir = Viewer_obj->phys_info.vel;
3448 vm_vec_normalize(&move_dir);
3451 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3452 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3453 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3454 vm_vec_normalize(&eye_dir);
3456 // JAS: I added the following code because if you slew up using
3457 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3458 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3459 // call because the up and the forward vector are the same. I fixed
3460 // it by adding in a fraction of the right vector all the time to the
3462 vector tmp_up = Viewer_obj->orient.uvec;
3463 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3465 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3468 // Modify the orientation based on head orientation.
3469 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3470 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3471 *eye_pos = Camera_pos;
3473 ship * shipp = &Ships[Player_obj->instance];
3475 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3476 vm_vec_normalize(&eye_dir);
3477 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3480 // get an eye position based upon the correct type of object
3481 switch(Viewer_obj->type){
3483 // make a call to get the eye point for the player object
3484 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3487 // make a call to get the eye point for the player object
3488 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3494 #ifdef JOHNS_DEBUG_CODE
3495 john_debug_stuff(&eye_pos, &eye_orient);
3501 apply_hud_shake(eye_orient);
3503 // setup neb2 rendering
3504 neb2_render_setup(eye_pos, eye_orient);
3508 extern void ai_debug_render_stuff();
3511 int Game_subspace_effect = 0;
3512 DCF_BOOL( subspace, Game_subspace_effect );
3514 // Does everything needed to render a frame
3515 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3519 g3_start_frame(game_zbuffer);
3520 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3522 // maybe offset the HUD (jitter stuff)
3523 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3524 HUD_set_offsets(Viewer_obj, !dont_offset);
3526 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3527 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3528 // must be done before ships are rendered
3529 if ( MULTIPLAYER_CLIENT ) {
3530 shield_point_multi_setup();
3533 if ( Game_subspace_effect ) {
3534 stars_draw(0,0,0,1);
3536 stars_draw(1,1,1,0);
3539 obj_render_all(obj_render);
3540 beam_render_all(); // render all beam weapons
3541 particle_render_all(); // render particles after everything else.
3542 trail_render_all(); // render missilie trails after everything else.
3543 mflash_render_all(); // render all muzzle flashes
3545 // Why do we not show the shield effect in these modes? Seems ok.
3546 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3550 // render nebula lightning
3553 // render local player nebula
3554 neb2_render_player();
3557 ai_debug_render_stuff();
3560 #ifndef RELEASE_REAL
3561 // game_framerate_check();
3565 extern void snd_spew_debug_info();
3566 snd_spew_debug_info();
3569 //================ END OF 3D RENDERING STUFF ====================
3573 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3574 hud_maybe_clear_head_area();
3575 anim_render_all(0, flFrametime);
3578 extern int Multi_display_netinfo;
3579 if(Multi_display_netinfo){
3580 extern void multi_display_netinfo();
3581 multi_display_netinfo();
3584 game_tst_frame_pre();
3587 do_timing_test(flFrametime);
3591 extern int OO_update_index;
3592 multi_rate_display(OO_update_index, 375, 0);
3597 extern void oo_display();
3604 //#define JOHNS_DEBUG_CODE 1
3606 #ifdef JOHNS_DEBUG_CODE
3607 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3609 //if ( keyd_pressed[KEY_LSHIFT] )
3611 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3613 model_subsystem *turret = tsys->system_info;
3615 if (turret->type == SUBSYSTEM_TURRET ) {
3617 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3619 ship_model_start(tobj);
3621 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3622 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3623 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3625 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3627 ship_model_stop(tobj);
3637 // following function for dumping frames for purposes of building trailers.
3640 // function to toggle state of dumping every frame into PCX when playing the game
3641 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3645 if ( Debug_dump_frames == 0 ) {
3647 Debug_dump_frames = 15;
3648 Debug_dump_trigger = 0;
3649 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3650 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3653 Debug_dump_frames = 0;
3654 Debug_dump_trigger = 0;
3655 gr_dump_frame_stop();
3656 dc_printf( "Frame dumping is now OFF\n" );
3662 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3666 if ( Debug_dump_frames == 0 ) {
3668 Debug_dump_frames = 15;
3669 Debug_dump_trigger = 1;
3670 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3671 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3674 Debug_dump_frames = 0;
3675 Debug_dump_trigger = 0;
3676 gr_dump_frame_stop();
3677 dc_printf( "Frame dumping is now OFF\n" );
3683 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3687 if ( Debug_dump_frames == 0 ) {
3689 Debug_dump_frames = 30;
3690 Debug_dump_trigger = 0;
3691 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3692 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3695 Debug_dump_frames = 0;
3696 Debug_dump_trigger = 0;
3697 gr_dump_frame_stop();
3698 dc_printf( "Frame dumping is now OFF\n" );
3704 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3708 if ( Debug_dump_frames == 0 ) {
3710 Debug_dump_frames = 30;
3711 Debug_dump_trigger = 1;
3712 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3713 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3716 Debug_dump_frames = 0;
3717 Debug_dump_trigger = 0;
3718 gr_dump_frame_stop();
3719 dc_printf( "Triggered frame dumping is now OFF\n" );
3725 void game_maybe_dump_frame()
3727 if ( !Debug_dump_frames ){
3731 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3738 Debug_dump_frame_num++;
3744 extern int Player_dead_state;
3746 // Flip the page and time how long it took.
3747 void game_flip_page_and_time_it()
3751 t1 = timer_get_fixed_seconds();
3753 t2 = timer_get_fixed_seconds();
3755 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3756 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3759 void game_simulation_frame()
3761 // blow ships up in multiplayer dogfight
3762 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){
3763 // blow up all non-player ships
3764 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3767 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3769 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)){
3770 moveup = GET_NEXT(moveup);
3773 shipp = &Ships[Objects[moveup->objnum].instance];
3774 sip = &Ship_info[shipp->ship_info_index];
3776 // only blow up small ships
3777 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3778 // function to simply explode a ship where it is currently at
3779 ship_self_destruct( &Objects[moveup->objnum] );
3782 moveup = GET_NEXT(moveup);
3788 // process AWACS stuff - do this first thing
3791 // single player, set Player hits_this_frame to 0
3792 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3793 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3794 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3798 supernova_process();
3799 if(supernova_active() >= 5){
3803 // fire targeting lasers now so that
3804 // 1 - created this frame
3805 // 2 - collide this frame
3806 // 3 - render this frame
3807 // 4 - ignored and deleted next frame
3808 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3810 ship_process_targeting_lasers();
3812 // do this here so that it works for multiplayer
3814 // get viewer direction
3815 int viewer_direction = PHYSICS_VIEWER_REAR;
3817 if(Viewer_mode == 0){
3818 viewer_direction = PHYSICS_VIEWER_FRONT;
3820 if(Viewer_mode & VM_PADLOCK_UP){
3821 viewer_direction = PHYSICS_VIEWER_UP;
3823 else if(Viewer_mode & VM_PADLOCK_REAR){
3824 viewer_direction = PHYSICS_VIEWER_REAR;
3826 else if(Viewer_mode & VM_PADLOCK_LEFT){
3827 viewer_direction = PHYSICS_VIEWER_LEFT;
3829 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3830 viewer_direction = PHYSICS_VIEWER_RIGHT;
3833 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3835 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3838 #define VM_PADLOCK_UP (1 << 7)
3839 #define VM_PADLOCK_REAR (1 << 8)
3840 #define VM_PADLOCK_LEFT (1 << 9)
3841 #define VM_PADLOCK_RIGHT (1 << 10)
3843 // evaluate mission departures and arrivals before we process all objects.
3844 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3846 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3847 // ships/wing packets.
3848 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3849 mission_parse_eval_stuff();
3852 // if we're an observer, move ourselves seperately from the standard physics
3853 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3854 obj_observer_move(flFrametime);
3857 // move all the objects now
3858 obj_move_all(flFrametime);
3860 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3861 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3862 // ship_check_cargo_all();
3863 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3864 mission_eval_goals();
3868 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3869 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3870 training_check_objectives();
3873 // do all interpolation now
3874 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3875 // client side processing of warping in effect stages
3876 multi_do_client_warp(flFrametime);
3878 // client side movement of an observer
3879 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3880 obj_observer_move(flFrametime);
3883 // move all objects - does interpolation now as well
3884 obj_move_all(flFrametime);
3887 // only process the message queue when the player is "in" the game
3888 if ( !Pre_player_entry ){
3889 message_queue_process(); // process any messages send to the player
3892 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3893 message_maybe_distort(); // maybe distort incoming message if comms damaged
3894 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3895 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3896 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3899 if(!(Game_mode & GM_STANDALONE_SERVER)){
3900 // process some stuff every frame (before frame is rendered)
3901 emp_process_local();
3903 hud_update_frame(); // update hud systems
3905 if (!physics_paused) {
3906 // Move particle system
3907 particle_move_all(flFrametime);
3909 // Move missile trails
3910 trail_move_all(flFrametime);
3912 // process muzzle flashes
3913 mflash_process_all();
3915 // Flash the gun flashes
3916 shipfx_flash_do_frame(flFrametime);
3918 shockwave_move_all(flFrametime); // update all the shockwaves
3921 // subspace missile strikes
3924 obj_snd_do_frame(); // update the object-linked persistant sounds
3925 game_maybe_update_sound_environment();
3926 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3928 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3930 if ( Game_subspace_effect ) {
3931 game_start_subspace_ambient_sound();
3937 // Maybe render and process the dead-popup
3938 void game_maybe_do_dead_popup(float frametime)
3940 if ( popupdead_is_active() ) {
3942 int choice = popupdead_do_frame(frametime);
3944 if ( Game_mode & GM_NORMAL ) {
3948 if(game_do_cd_mission_check(Game_current_mission_filename)){
3949 gameseq_post_event(GS_EVENT_ENTER_GAME);
3951 gameseq_post_event(GS_EVENT_MAIN_MENU);
3956 gameseq_post_event(GS_EVENT_END_GAME);
3961 if(game_do_cd_mission_check(Game_current_mission_filename)){
3962 gameseq_post_event(GS_EVENT_START_GAME);
3964 gameseq_post_event(GS_EVENT_MAIN_MENU);
3968 // this should only happen during a red alert mission
3971 Assert(The_mission.red_alert);
3972 if(!The_mission.red_alert){
3974 if(game_do_cd_mission_check(Game_current_mission_filename)){
3975 gameseq_post_event(GS_EVENT_START_GAME);
3977 gameseq_post_event(GS_EVENT_MAIN_MENU);
3982 // choose the previous mission
3983 mission_campaign_previous_mission();
3985 if(game_do_cd_mission_check(Game_current_mission_filename)){
3986 gameseq_post_event(GS_EVENT_START_GAME);
3988 gameseq_post_event(GS_EVENT_MAIN_MENU);
3999 case POPUPDEAD_DO_MAIN_HALL:
4000 multi_quit_game(PROMPT_NONE,-1);
4003 case POPUPDEAD_DO_RESPAWN:
4004 multi_respawn_normal();
4005 event_music_player_respawn();
4008 case POPUPDEAD_DO_OBSERVER:
4009 multi_respawn_observer();
4010 event_music_player_respawn_as_observer();
4019 if ( leave_popup ) {
4025 // returns true if player is actually in a game_play stats
4026 int game_actually_playing()
4030 state = gameseq_get_state();
4031 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4037 // Draw the 2D HUD gauges
4038 void game_render_hud_2d()
4040 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4044 HUD_render_2d(flFrametime);
4048 // Draw the 3D-dependant HUD gauges
4049 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4051 g3_start_frame(0); // 0 = turn zbuffering off
4052 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4054 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4055 HUD_render_3d(flFrametime);
4059 game_sunspot_process(flFrametime);
4061 // Diminish the palette effect
4062 game_flash_diminish(flFrametime);
4070 int actually_playing;
4071 fix total_time1, total_time2;
4072 fix render2_time1=0, render2_time2=0;
4073 fix render3_time1=0, render3_time2=0;
4074 fix flip_time1=0, flip_time2=0;
4075 fix clear_time1=0, clear_time2=0;
4081 if (Framerate_delay) {
4082 int start_time = timer_get_milliseconds();
4083 while (timer_get_milliseconds() < start_time + Framerate_delay)
4089 demo_do_frame_start();
4091 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4096 // start timing frame
4097 timing_frame_start();
4099 total_time1 = timer_get_fixed_seconds();
4101 // var to hold which state we are in
4102 actually_playing = game_actually_playing();
4104 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4105 if (!(Game_mode & GM_STANDALONE_SERVER)){
4106 Assert( OBJ_INDEX(Player_obj) >= 0 );
4110 if (Missiontime > Entry_delay_time){
4111 Pre_player_entry = 0;
4113 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4116 // Note: These are done even before the player enters, else buffers can overflow.
4117 if (! (Game_mode & GM_STANDALONE_SERVER)){
4121 shield_frame_init();
4123 if ( Player->control_mode != PCM_NORMAL )
4126 if ( !Pre_player_entry && actually_playing ) {
4127 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4129 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4130 game_process_keys();
4132 // don't read flying controls if we're playing a demo back
4133 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4134 read_player_controls( Player_obj, flFrametime);
4138 // if we're not the master, we may have to send the server-critical ship status button_info bits
4139 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4140 multi_maybe_send_ship_status();
4145 // Reset the whack stuff
4148 // These two lines must be outside of Pre_player_entry code,
4149 // otherwise too many lights are added.
4152 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4156 game_simulation_frame();
4158 // if not actually in a game play state, then return. This condition could only be true in
4159 // a multiplayer game.
4160 if ( !actually_playing ) {
4161 Assert( Game_mode & GM_MULTIPLAYER );
4165 if (!Pre_player_entry) {
4166 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4167 clear_time1 = timer_get_fixed_seconds();
4168 // clear the screen to black
4170 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4174 clear_time2 = timer_get_fixed_seconds();
4175 render3_time1 = timer_get_fixed_seconds();
4176 game_render_frame_setup(&eye_pos, &eye_orient);
4177 game_render_frame( &eye_pos, &eye_orient );
4179 // save the eye position and orientation
4180 if ( Game_mode & GM_MULTIPLAYER ) {
4181 Net_player->s_info.eye_pos = eye_pos;
4182 Net_player->s_info.eye_orient = eye_orient;
4185 hud_show_target_model();
4187 // check to see if we should display the death died popup
4188 if(Game_mode & GM_DEAD_BLEW_UP){
4189 if(Game_mode & GM_MULTIPLAYER){
4190 // catch the situation where we're supposed to be warping out on this transition
4191 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4192 gameseq_post_event(GS_EVENT_DEBRIEF);
4193 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4194 Player_died_popup_wait = -1;
4198 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4199 Player_died_popup_wait = -1;
4205 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4206 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4207 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4208 if(!popupdead_is_active()){
4212 Player_multi_died_check = -1;
4216 render3_time2 = timer_get_fixed_seconds();
4217 render2_time1 = timer_get_fixed_seconds();
4220 game_get_framerate();
4221 game_show_framerate();
4223 game_show_time_left();
4225 // Draw the 2D HUD gauges
4226 if(supernova_active() < 3){
4227 game_render_hud_2d();
4230 game_set_view_clip();
4232 // Draw 3D HUD gauges
4233 game_render_hud_3d(&eye_pos, &eye_orient);
4237 render2_time2 = timer_get_fixed_seconds();
4239 // maybe render and process the dead popup
4240 game_maybe_do_dead_popup(flFrametime);
4242 // start timing frame
4243 timing_frame_stop();
4244 // timing_display(30, 10);
4246 // If a regular popup is active, don't flip (popup code flips)
4247 if( !popup_running_state() ){
4248 flip_time1 = timer_get_fixed_seconds();
4249 game_flip_page_and_time_it();
4250 flip_time2 = timer_get_fixed_seconds();
4254 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4257 game_show_standalone_framerate();
4261 game_do_training_checks();
4264 // process lightning (nebula only)
4267 total_time2 = timer_get_fixed_seconds();
4269 // Got some timing numbers
4270 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4271 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4272 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4273 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4274 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4277 demo_do_frame_end();
4279 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4285 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4286 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4287 // died. This resulted in screwed up death sequences.
4289 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4290 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4291 static int timer_paused=0;
4292 static int stop_count,start_count;
4293 static int time_stopped,time_started;
4294 int saved_timestamp_ticker = -1;
4296 void game_reset_time()
4298 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4302 // Last_time = timer_get_fixed_seconds();
4308 void game_stop_time()
4310 if (timer_paused==0) {
4312 time = timer_get_fixed_seconds();
4313 // Save how much time progressed so far in the frame so we can
4314 // use it when we unpause.
4315 Last_delta_time = time - Last_time;
4317 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4318 if (Last_delta_time < 0) {
4319 #if defined(TIMER_TEST) && !defined(NDEBUG)
4320 Int3(); //get Matt!!!!
4322 Last_delta_time = 0;
4324 #if defined(TIMER_TEST) && !defined(NDEBUG)
4325 time_stopped = time;
4328 // Stop the timer_tick stuff...
4329 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4330 saved_timestamp_ticker = timestamp_ticker;
4334 #if defined(TIMER_TEST) && !defined(NDEBUG)
4339 void game_start_time()
4342 Assert(timer_paused >= 0);
4343 if (timer_paused==0) {
4345 time = timer_get_fixed_seconds();
4346 #if defined(TIMER_TEST) && !defined(NDEBUG)
4348 Int3(); //get Matt!!!!
4351 // Take current time, and set it backwards to account for time
4352 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4353 // will be correct when it goes to calculate the frametime next
4355 Last_time = time - Last_delta_time;
4356 #if defined(TIMER_TEST) && !defined(NDEBUG)
4357 time_started = time;
4360 // Restore the timer_tick stuff...
4361 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4362 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4363 timestamp_ticker = saved_timestamp_ticker;
4364 saved_timestamp_ticker = -1;
4367 #if defined(TIMER_TEST) && !defined(NDEBUG)
4373 void game_set_frametime(int state)
4376 float frame_cap_diff;
4378 thistime = timer_get_fixed_seconds();
4380 if ( Last_time == 0 )
4381 Frametime = F1_0 / 30;
4383 Frametime = thistime - Last_time;
4385 // Frametime = F1_0 / 30;
4387 fix debug_frametime = Frametime; // Just used to display frametime.
4389 // If player hasn't entered mission yet, make frame take 1/4 second.
4390 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4393 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4395 fix frame_speed = F1_0 / Debug_dump_frames;
4397 if (Frametime > frame_speed ){
4398 nprintf(("warning","slow frame: %x\n",Frametime));
4401 thistime = timer_get_fixed_seconds();
4402 Frametime = thistime - Last_time;
4403 } while (Frametime < frame_speed );
4405 Frametime = frame_speed;
4409 Assert( Framerate_cap > 0 );
4411 // Cap the framerate so it doesn't get too high.
4415 cap = F1_0/Framerate_cap;
4416 if (Frametime < cap) {
4417 thistime = cap - Frametime;
4418 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4419 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4421 thistime = timer_get_fixed_seconds();
4425 if((Game_mode & GM_STANDALONE_SERVER) &&
4426 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4428 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4429 Sleep((DWORD)(frame_cap_diff*1000));
4431 thistime += fl2f((frame_cap_diff));
4433 Frametime = thistime - Last_time;
4436 // If framerate is too low, cap it.
4437 if (Frametime > MAX_FRAMETIME) {
4439 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4441 // to remove warnings in release build
4442 debug_frametime = fl2f(flFrametime);
4444 Frametime = MAX_FRAMETIME;
4447 Frametime = fixmul(Frametime, Game_time_compression);
4449 Last_time = thistime;
4450 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4452 flFrametime = f2fl(Frametime);
4453 //if(!(Game_mode & GM_PLAYING_DEMO)){
4454 timestamp_inc(flFrametime);
4456 /* if ((Framecount > 0) && (Framecount < 10)) {
4457 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4462 // This is called from game_do_frame(), and from navmap_do_frame()
4463 void game_update_missiontime()
4465 // TODO JAS: Put in if and move this into game_set_frametime,
4466 // fix navmap to call game_stop/start_time
4467 //if ( !timer_paused )
4468 Missiontime += Frametime;
4471 void game_do_frame()
4473 game_set_frametime(GS_STATE_GAME_PLAY);
4474 game_update_missiontime();
4476 if (Game_mode & GM_STANDALONE_SERVER) {
4477 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4480 if ( game_single_step && (last_single_step == game_single_step) ) {
4481 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4482 while( key_checkch() == 0 )
4484 os_set_title( XSTR( "FreeSpace", 171) );
4485 Last_time = timer_get_fixed_seconds();
4488 last_single_step = game_single_step;
4490 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4491 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4495 Keep_mouse_centered = 0;
4496 monitor_update(); // Update monitor variables
4499 void multi_maybe_do_frame()
4501 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4506 int Joymouse_button_status = 0;
4508 // Flush all input devices
4516 Joymouse_button_status = 0;
4518 //mprintf(("Game flush!\n" ));
4521 // function for multiplayer only which calls game_do_state_common() when running the
4523 void game_do_dc_networking()
4525 Assert( Game_mode & GM_MULTIPLAYER );
4527 game_do_state_common( gameseq_get_state() );
4530 // Call this whenever in a loop, or when you need to check for a keystroke.
4531 int game_check_key()
4537 // convert keypad enter to normal enter
4538 if ((k & KEY_MASK) == KEY_PADENTER)
4539 k = (k & ~KEY_MASK) | KEY_ENTER;
4546 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4547 static int Demo_show_trailer_timestamp = 0;
4549 void demo_reset_trailer_timer()
4551 Demo_show_trailer_timestamp = timer_get_milliseconds();
4554 void demo_maybe_show_trailer(int k)
4557 // if key pressed, reset demo trailer timer
4559 demo_reset_trailer_timer();
4563 // if mouse moved, reset demo trailer timer
4566 mouse_get_delta(&dx, &dy);
4567 if ( (dx > 0) || (dy > 0) ) {
4568 demo_reset_trailer_timer();
4572 // if joystick has moved, reset demo trailer timer
4575 joy_get_delta(&dx, &dy);
4576 if ( (dx > 0) || (dy > 0) ) {
4577 demo_reset_trailer_timer();
4581 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4582 // the low-level code. Ugly, I know... but was the simplest and most
4585 // if 30 seconds since last demo trailer time reset, launch movie
4586 if ( os_foreground() ) {
4587 int now = timer_get_milliseconds();
4588 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4589 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4591 movie_play( NOX("fstrailer2.mve") );
4592 demo_reset_trailer_timer();
4600 // same as game_check_key(), except this is used while actually in the game. Since there
4601 // generally are differences between game control keys and general UI keys, makes sense to
4602 // have seperate functions for each case. If you are not checking a game control while in a
4603 // mission, you should probably be using game_check_key() instead.
4608 if (!os_foreground()) {
4613 // If we're in a single player game, pause it.
4614 if (!(Game_mode & GM_MULTIPLAYER)){
4615 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4616 game_process_pause_key();
4624 demo_maybe_show_trailer(k);
4627 // Move the mouse cursor with the joystick.
4628 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4629 // Move the mouse cursor with the joystick
4633 joy_get_pos( &jx, &jy, &jz, &jr );
4635 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4636 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4639 mouse_get_real_pos( &mx, &my );
4640 mouse_set_pos( mx+dx, my+dy );
4645 m = mouse_down(MOUSE_LEFT_BUTTON);
4647 if ( j != Joymouse_button_status ) {
4648 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4649 Joymouse_button_status = j;
4651 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4652 } else if ( (!j) && (m) ) {
4653 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4658 // if we should be ignoring keys because of some multiplayer situations
4659 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4663 // If a popup is running, don't process all the Fn keys
4664 if( popup_active() ) {
4668 state = gameseq_get_state();
4670 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4673 case KEY_DEBUGGED + KEY_BACKSP:
4678 launch_context_help();
4683 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4685 // don't allow f2 while warping out in multiplayer
4686 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4691 case GS_STATE_INITIAL_PLAYER_SELECT:
4692 case GS_STATE_OPTIONS_MENU:
4693 case GS_STATE_HUD_CONFIG:
4694 case GS_STATE_CONTROL_CONFIG:
4695 case GS_STATE_DEATH_DIED:
4696 case GS_STATE_DEATH_BLEW_UP:
4697 case GS_STATE_VIEW_MEDALS:
4701 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4708 // hotkey selection screen -- only valid from briefing and beyond.
4711 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) ) {
4712 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4718 case KEY_DEBUGGED + KEY_F3:
4719 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4722 case KEY_DEBUGGED + KEY_F4:
4723 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4727 if(Game_mode & GM_MULTIPLAYER){
4728 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4729 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4733 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4734 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4740 case KEY_ESC | KEY_SHIFTED:
4741 // make sure to quit properly out of multiplayer
4742 if(Game_mode & GM_MULTIPLAYER){
4743 multi_quit_game(PROMPT_NONE);
4746 gameseq_post_event( GS_EVENT_QUIT_GAME );
4751 case KEY_DEBUGGED + KEY_P:
4754 case KEY_PRINT_SCRN:
4756 static int counter = 0;
4761 sprintf( tmp_name, NOX("screen%02d"), counter );
4763 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4764 gr_print_screen(tmp_name);
4772 case KEY_SHIFTED | KEY_ENTER: {
4774 #if !defined(NDEBUG)
4776 if ( Game_mode & GM_NORMAL ){
4780 // if we're in multiplayer mode, do some special networking
4781 if(Game_mode & GM_MULTIPLAYER){
4782 debug_console(game_do_dc_networking);
4789 if ( Game_mode & GM_NORMAL )
4803 gameseq_post_event(GS_EVENT_QUIT_GAME);
4806 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4809 void camera_set_position( vector *pos )
4814 void camera_set_orient( matrix *orient )
4816 Camera_orient = *orient;
4819 void camera_set_velocity( vector *vel, int instantaneous )
4821 Camera_desired_velocity.x = 0.0f;
4822 Camera_desired_velocity.y = 0.0f;
4823 Camera_desired_velocity.z = 0.0f;
4825 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4826 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4827 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4829 if ( instantaneous ) {
4830 Camera_velocity = Camera_desired_velocity;
4838 vector new_vel, delta_pos;
4840 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4841 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4842 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4844 Camera_velocity = new_vel;
4846 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4848 vm_vec_add2( &Camera_pos, &delta_pos );
4850 float ot = Camera_time+0.0f;
4852 Camera_time += flFrametime;
4854 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4857 tmp.z = 4.739f; // always go this fast forward.
4859 // pick x and y velocities so they are always on a
4860 // circle with a 25 m radius.
4862 float tmp_angle = frand()*PI2;
4864 tmp.x = 22.0f * (float)sin(tmp_angle);
4865 tmp.y = -22.0f * (float)cos(tmp_angle);
4867 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4869 //mprintf(( "Changing velocity!\n" ));
4870 camera_set_velocity( &tmp, 0 );
4873 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4874 vector tmp = { 0.0f, 0.0f, 0.0f };
4875 camera_set_velocity( &tmp, 0 );
4880 void end_demo_campaign_do()
4882 #if defined(FS2_DEMO)
4883 // show upsell screens
4884 demo_upsell_show_screens();
4885 #elif defined(OEM_BUILD)
4886 // show oem upsell screens
4887 oem_upsell_show_screens();
4890 // drop into main hall
4891 gameseq_post_event( GS_EVENT_MAIN_MENU );
4894 // All code to process events. This is the only place
4895 // that you should change the state of the game.
4896 void game_process_event( int current_state, int event )
4898 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4901 case GS_EVENT_SIMULATOR_ROOM:
4902 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4905 case GS_EVENT_MAIN_MENU:
4906 gameseq_set_state(GS_STATE_MAIN_MENU);
4909 case GS_EVENT_OPTIONS_MENU:
4910 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4913 case GS_EVENT_BARRACKS_MENU:
4914 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4917 case GS_EVENT_TECH_MENU:
4918 gameseq_set_state(GS_STATE_TECH_MENU);
4921 case GS_EVENT_TRAINING_MENU:
4922 gameseq_set_state(GS_STATE_TRAINING_MENU);
4925 case GS_EVENT_START_GAME:
4926 Select_default_ship = 0;
4927 Player_multi_died_check = -1;
4928 gameseq_set_state(GS_STATE_CMD_BRIEF);
4931 case GS_EVENT_START_BRIEFING:
4932 gameseq_set_state(GS_STATE_BRIEFING);
4935 case GS_EVENT_DEBRIEF:
4936 // did we end the campaign in the main freespace 2 single player campaign?
4937 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4938 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4940 gameseq_set_state(GS_STATE_DEBRIEF);
4943 Player_multi_died_check = -1;
4946 case GS_EVENT_SHIP_SELECTION:
4947 gameseq_set_state( GS_STATE_SHIP_SELECT );
4950 case GS_EVENT_WEAPON_SELECTION:
4951 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4954 case GS_EVENT_ENTER_GAME:
4956 // maybe start recording a demo
4958 demo_start_record("test.fsd");
4962 if (Game_mode & GM_MULTIPLAYER) {
4963 // if we're respawning, make sure we change the view mode so that the hud shows up
4964 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4968 gameseq_set_state(GS_STATE_GAME_PLAY);
4970 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4973 Player_multi_died_check = -1;
4975 // clear multiplayer button info
4976 extern button_info Multi_ship_status_bi;
4977 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4979 Start_time = f2fl(timer_get_approx_seconds());
4981 mprintf(("Entering game at time = %7.3f\n", Start_time));
4985 case GS_EVENT_START_GAME_QUICK:
4986 Select_default_ship = 1;
4987 gameseq_post_event(GS_EVENT_ENTER_GAME);
4991 case GS_EVENT_END_GAME:
4992 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4993 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4994 gameseq_set_state(GS_STATE_MAIN_MENU);
4999 Player_multi_died_check = -1;
5002 case GS_EVENT_QUIT_GAME:
5003 main_hall_stop_music();
5004 main_hall_stop_ambient();
5005 gameseq_set_state(GS_STATE_QUIT_GAME);
5007 Player_multi_died_check = -1;
5010 case GS_EVENT_GAMEPLAY_HELP:
5011 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5014 case GS_EVENT_PAUSE_GAME:
5015 gameseq_push_state(GS_STATE_GAME_PAUSED);
5018 case GS_EVENT_DEBUG_PAUSE_GAME:
5019 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5022 case GS_EVENT_TRAINING_PAUSE:
5023 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5026 case GS_EVENT_PREVIOUS_STATE:
5027 gameseq_pop_state();
5030 case GS_EVENT_TOGGLE_FULLSCREEN:
5031 #ifndef HARDWARE_ONLY
5033 if ( gr_screen.mode == GR_SOFTWARE ) {
5034 gr_init( GR_640, GR_DIRECTDRAW );
5035 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5036 gr_init( GR_640, GR_SOFTWARE );
5042 case GS_EVENT_TOGGLE_GLIDE:
5044 if ( gr_screen.mode != GR_GLIDE ) {
5045 gr_init( GR_640, GR_GLIDE );
5047 gr_init( GR_640, GR_SOFTWARE );
5052 case GS_EVENT_LOAD_MISSION_MENU:
5053 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5056 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5057 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5060 case GS_EVENT_HUD_CONFIG:
5061 gameseq_push_state( GS_STATE_HUD_CONFIG );
5064 case GS_EVENT_CONTROL_CONFIG:
5065 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5068 case GS_EVENT_DEATH_DIED:
5069 gameseq_set_state( GS_STATE_DEATH_DIED );
5072 case GS_EVENT_DEATH_BLEW_UP:
5073 if ( current_state == GS_STATE_DEATH_DIED ) {
5074 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5075 event_music_player_death();
5077 // multiplayer clients set their extra check here
5078 if(Game_mode & GM_MULTIPLAYER){
5079 // set the multi died absolute last chance check
5080 Player_multi_died_check = time(NULL);
5083 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5087 case GS_EVENT_NEW_CAMPAIGN:
5088 if (!mission_load_up_campaign()){
5089 readyroom_continue_campaign();
5092 Player_multi_died_check = -1;
5095 case GS_EVENT_CAMPAIGN_CHEAT:
5096 if (!mission_load_up_campaign()){
5098 // bash campaign value
5099 extern char Main_hall_campaign_cheat[512];
5102 // look for the mission
5103 for(idx=0; idx<Campaign.num_missions; idx++){
5104 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5105 Campaign.next_mission = idx;
5106 Campaign.prev_mission = idx - 1;
5113 readyroom_continue_campaign();
5116 Player_multi_died_check = -1;
5119 case GS_EVENT_CAMPAIGN_ROOM:
5120 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5123 case GS_EVENT_CMD_BRIEF:
5124 gameseq_set_state(GS_STATE_CMD_BRIEF);
5127 case GS_EVENT_RED_ALERT:
5128 gameseq_set_state(GS_STATE_RED_ALERT);
5131 case GS_EVENT_CREDITS:
5132 gameseq_set_state( GS_STATE_CREDITS );
5135 case GS_EVENT_VIEW_MEDALS:
5136 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5139 case GS_EVENT_SHOW_GOALS:
5140 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5143 case GS_EVENT_HOTKEY_SCREEN:
5144 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5147 // multiplayer stuff follow these comments
5149 case GS_EVENT_MULTI_JOIN_GAME:
5150 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5153 case GS_EVENT_MULTI_HOST_SETUP:
5154 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5157 case GS_EVENT_MULTI_CLIENT_SETUP:
5158 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5161 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5162 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5165 case GS_EVENT_MULTI_STD_WAIT:
5166 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5169 case GS_EVENT_STANDALONE_MAIN:
5170 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5173 case GS_EVENT_MULTI_PAUSE:
5174 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5177 case GS_EVENT_INGAME_PRE_JOIN:
5178 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5181 case GS_EVENT_EVENT_DEBUG:
5182 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5185 // Start a warpout where player automatically goes 70 no matter what
5186 // and can't cancel out of it.
5187 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5188 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5190 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5191 Player->saved_viewer_mode = Viewer_mode;
5192 Player->control_mode = PCM_WARPOUT_STAGE1;
5193 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5194 Warpout_time = 0.0f; // Start timer!
5197 case GS_EVENT_PLAYER_WARPOUT_START:
5198 if ( Player->control_mode != PCM_NORMAL ) {
5199 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5201 Player->saved_viewer_mode = Viewer_mode;
5202 Player->control_mode = PCM_WARPOUT_STAGE1;
5203 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5204 Warpout_time = 0.0f; // Start timer!
5205 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5209 case GS_EVENT_PLAYER_WARPOUT_STOP:
5210 if ( Player->control_mode != PCM_NORMAL ) {
5211 if ( !Warpout_forced ) { // cannot cancel forced warpout
5212 Player->control_mode = PCM_NORMAL;
5213 Viewer_mode = Player->saved_viewer_mode;
5214 hud_subspace_notify_abort();
5215 mprintf(( "Player put back to normal mode.\n" ));
5216 if ( Warpout_sound > -1 ) {
5217 snd_stop( Warpout_sound );
5224 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5225 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5226 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5227 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5229 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5230 shipfx_warpout_start( Player_obj );
5231 Player->control_mode = PCM_WARPOUT_STAGE2;
5232 Player->saved_viewer_mode = Viewer_mode;
5233 Viewer_mode |= VM_WARP_CHASE;
5235 vector tmp = Player_obj->pos;
5237 ship_get_eye( &tmp, &tmp_m, Player_obj );
5238 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5239 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5240 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5242 camera_set_position( &tmp );
5243 camera_set_orient( &Player_obj->orient );
5244 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5246 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5247 camera_set_velocity( &tmp_vel, 1);
5251 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5252 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5253 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5254 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5256 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5257 Player->control_mode = PCM_WARPOUT_STAGE3;
5261 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5262 mprintf(( "Player warped out. Going to debriefing!\n" ));
5263 Player->control_mode = PCM_NORMAL;
5264 Viewer_mode = Player->saved_viewer_mode;
5267 // we have a special debriefing screen for multiplayer furballs
5268 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5269 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5271 // do the normal debriefing for all other situations
5273 gameseq_post_event(GS_EVENT_DEBRIEF);
5277 case GS_EVENT_STANDALONE_POSTGAME:
5278 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5281 case GS_EVENT_INITIAL_PLAYER_SELECT:
5282 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5285 case GS_EVENT_GAME_INIT:
5286 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5287 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5289 // see if the command line option has been set to use the last pilot, and act acoordingly
5290 if( player_select_get_last_pilot() ) {
5291 // always enter the main menu -- do the automatic network startup stuff elsewhere
5292 // so that we still have valid checks for networking modes, etc.
5293 gameseq_set_state(GS_STATE_MAIN_MENU);
5295 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5300 case GS_EVENT_MULTI_MISSION_SYNC:
5301 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5304 case GS_EVENT_MULTI_START_GAME:
5305 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5308 case GS_EVENT_MULTI_HOST_OPTIONS:
5309 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5312 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5313 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5316 case GS_EVENT_TEAM_SELECT:
5317 gameseq_set_state(GS_STATE_TEAM_SELECT);
5320 case GS_EVENT_END_CAMPAIGN:
5321 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5324 case GS_EVENT_END_DEMO:
5325 gameseq_set_state(GS_STATE_END_DEMO);
5328 case GS_EVENT_LOOP_BRIEF:
5329 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5338 // Called when a state is being left.
5339 // The current state is still at old_state, but as soon as
5340 // this function leaves, then the current state will become
5341 // new state. You should never try to change the state
5342 // in here... if you think you need to, you probably really
5343 // need to post an event, not change the state.
5344 void game_leave_state( int old_state, int new_state )
5346 int end_mission = 1;
5348 switch (new_state) {
5349 case GS_STATE_GAME_PAUSED:
5350 case GS_STATE_DEBUG_PAUSED:
5351 case GS_STATE_OPTIONS_MENU:
5352 case GS_STATE_CONTROL_CONFIG:
5353 case GS_STATE_MISSION_LOG_SCROLLBACK:
5354 case GS_STATE_DEATH_DIED:
5355 case GS_STATE_SHOW_GOALS:
5356 case GS_STATE_HOTKEY_SCREEN:
5357 case GS_STATE_MULTI_PAUSED:
5358 case GS_STATE_TRAINING_PAUSED:
5359 case GS_STATE_EVENT_DEBUG:
5360 case GS_STATE_GAMEPLAY_HELP:
5361 end_mission = 0; // these events shouldn't end a mission
5365 switch (old_state) {
5366 case GS_STATE_BRIEFING:
5367 brief_stop_voices();
5368 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5369 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5370 && (new_state != GS_STATE_TEAM_SELECT) ){
5371 common_select_close();
5372 if ( new_state == GS_STATE_MAIN_MENU ) {
5373 freespace_stop_mission();
5377 // COMMAND LINE OPTION
5378 if (Cmdline_multi_stream_chat_to_file){
5379 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5380 cfclose(Multi_chat_stream);
5384 case GS_STATE_DEBRIEF:
5385 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5390 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5391 multi_df_debrief_close();
5394 case GS_STATE_LOAD_MISSION_MENU:
5395 mission_load_menu_close();
5398 case GS_STATE_SIMULATOR_ROOM:
5402 case GS_STATE_CAMPAIGN_ROOM:
5403 campaign_room_close();
5406 case GS_STATE_CMD_BRIEF:
5407 if (new_state == GS_STATE_OPTIONS_MENU) {
5412 if (new_state == GS_STATE_MAIN_MENU)
5413 freespace_stop_mission();
5418 case GS_STATE_RED_ALERT:
5422 case GS_STATE_SHIP_SELECT:
5423 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5424 new_state != GS_STATE_HOTKEY_SCREEN &&
5425 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5426 common_select_close();
5427 if ( new_state == GS_STATE_MAIN_MENU ) {
5428 freespace_stop_mission();
5433 case GS_STATE_WEAPON_SELECT:
5434 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5435 new_state != GS_STATE_HOTKEY_SCREEN &&
5436 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5437 common_select_close();
5438 if ( new_state == GS_STATE_MAIN_MENU ) {
5439 freespace_stop_mission();
5444 case GS_STATE_TEAM_SELECT:
5445 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5446 new_state != GS_STATE_HOTKEY_SCREEN &&
5447 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5448 common_select_close();
5449 if ( new_state == GS_STATE_MAIN_MENU ) {
5450 freespace_stop_mission();
5455 case GS_STATE_MAIN_MENU:
5456 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5463 case GS_STATE_OPTIONS_MENU:
5464 //game_start_time();
5465 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5466 multi_join_clear_game_list();
5468 options_menu_close();
5471 case GS_STATE_BARRACKS_MENU:
5472 if(new_state != GS_STATE_VIEW_MEDALS){
5477 case GS_STATE_MISSION_LOG_SCROLLBACK:
5478 hud_scrollback_close();
5481 case GS_STATE_TRAINING_MENU:
5482 training_menu_close();
5485 case GS_STATE_GAME_PLAY:
5486 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5487 player_save_target_and_weapon_link_prefs();
5488 game_stop_looped_sounds();
5491 sound_env_disable();
5492 joy_ff_stop_effects();
5494 // stop game time under certain conditions
5495 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5500 // shut down any recording or playing demos
5505 // when in multiplayer and going back to the main menu, send a leave game packet
5506 // right away (before calling stop mission). stop_mission was taking to long to
5507 // close mission down and I want people to get notified ASAP.
5508 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5509 multi_quit_game(PROMPT_NONE);
5512 freespace_stop_mission();
5513 Game_time_compression = F1_0;
5517 case GS_STATE_TECH_MENU:
5521 case GS_STATE_TRAINING_PAUSED:
5522 Training_num_lines = 0;
5523 // fall through to GS_STATE_GAME_PAUSED
5525 case GS_STATE_GAME_PAUSED:
5527 if ( end_mission ) {
5532 case GS_STATE_DEBUG_PAUSED:
5535 pause_debug_close();
5539 case GS_STATE_HUD_CONFIG:
5543 // join/start a game
5544 case GS_STATE_MULTI_JOIN_GAME:
5545 if(new_state != GS_STATE_OPTIONS_MENU){
5546 multi_join_game_close();
5550 case GS_STATE_MULTI_HOST_SETUP:
5551 case GS_STATE_MULTI_CLIENT_SETUP:
5552 // if this is just the host going into the options screen, don't do anything
5553 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5557 // close down the proper state
5558 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5559 multi_create_game_close();
5561 multi_game_client_setup_close();
5564 // COMMAND LINE OPTION
5565 if (Cmdline_multi_stream_chat_to_file){
5566 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5567 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5568 cfclose(Multi_chat_stream);
5573 case GS_STATE_CONTROL_CONFIG:
5574 control_config_close();
5577 case GS_STATE_DEATH_DIED:
5578 Game_mode &= ~GM_DEAD_DIED;
5580 // early end while respawning or blowing up in a multiplayer game
5581 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5583 freespace_stop_mission();
5587 case GS_STATE_DEATH_BLEW_UP:
5588 Game_mode &= ~GM_DEAD_BLEW_UP;
5590 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5591 // to determine if I should do anything.
5592 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5594 freespace_stop_mission();
5597 // if we are not respawing as an observer or as a player, our new state will not
5598 // be gameplay state.
5599 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5600 game_stop_time(); // hasn't been called yet!!
5601 freespace_stop_mission();
5607 case GS_STATE_CREDITS:
5611 case GS_STATE_VIEW_MEDALS:
5615 case GS_STATE_SHOW_GOALS:
5616 mission_show_goals_close();
5619 case GS_STATE_HOTKEY_SCREEN:
5620 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5621 mission_hotkey_close();
5625 case GS_STATE_MULTI_MISSION_SYNC:
5626 // if we're moving into the options menu, don't do anything
5627 if(new_state == GS_STATE_OPTIONS_MENU){
5631 Assert( Game_mode & GM_MULTIPLAYER );
5633 if ( new_state == GS_STATE_GAME_PLAY ){
5634 // palette_restore_palette();
5636 // change a couple of flags to indicate our state!!!
5637 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5638 send_netplayer_update_packet();
5640 // set the game mode
5641 Game_mode |= GM_IN_MISSION;
5645 case GS_STATE_VIEW_CUTSCENES:
5646 cutscenes_screen_close();
5649 case GS_STATE_MULTI_STD_WAIT:
5650 multi_standalone_wait_close();
5653 case GS_STATE_STANDALONE_MAIN:
5654 standalone_main_close();
5655 if(new_state == GS_STATE_MULTI_STD_WAIT){
5656 init_multiplayer_stats();
5660 case GS_STATE_MULTI_PAUSED:
5661 // if ( end_mission ){
5666 case GS_STATE_INGAME_PRE_JOIN:
5667 multi_ingame_select_close();
5670 case GS_STATE_STANDALONE_POSTGAME:
5671 multi_standalone_postgame_close();
5674 case GS_STATE_INITIAL_PLAYER_SELECT:
5675 player_select_close();
5678 case GS_STATE_MULTI_START_GAME:
5679 multi_start_game_close();
5682 case GS_STATE_MULTI_HOST_OPTIONS:
5683 multi_host_options_close();
5686 case GS_STATE_END_OF_CAMPAIGN:
5687 mission_campaign_end_close();
5690 case GS_STATE_LOOP_BRIEF:
5696 // Called when a state is being entered.
5697 // The current state is set to the state we're entering at
5698 // this point, and old_state is set to the state we're coming
5699 // from. You should never try to change the state
5700 // in here... if you think you need to, you probably really
5701 // need to post an event, not change the state.
5703 void game_enter_state( int old_state, int new_state )
5705 switch (new_state) {
5706 case GS_STATE_MAIN_MENU:
5707 // in multiplayer mode, be sure that we are not doing networking anymore.
5708 if ( Game_mode & GM_MULTIPLAYER ) {
5709 Assert( Net_player != NULL );
5710 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5713 Game_time_compression = F1_0;
5715 // determine which ship this guy is currently based on
5716 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5719 if (Player->on_bastion) {
5727 case GS_STATE_BRIEFING:
5728 main_hall_stop_music();
5729 main_hall_stop_ambient();
5731 if (Game_mode & GM_NORMAL) {
5732 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5733 // MWA: or from options or hotkey screens
5734 // JH: or if the command brief state already did this
5735 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5736 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5737 && (old_state != GS_STATE_CMD_BRIEF) ) {
5738 if ( !game_start_mission() ) // this should put us into a new state on failure!
5742 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5743 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5744 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5746 Game_time_compression = F1_0;
5748 if ( red_alert_mission() ) {
5749 gameseq_post_event(GS_EVENT_RED_ALERT);
5756 case GS_STATE_DEBRIEF:
5757 game_stop_looped_sounds();
5758 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5759 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5764 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5765 multi_df_debrief_init();
5768 case GS_STATE_LOAD_MISSION_MENU:
5769 mission_load_menu_init();
5772 case GS_STATE_SIMULATOR_ROOM:
5776 case GS_STATE_CAMPAIGN_ROOM:
5777 campaign_room_init();
5780 case GS_STATE_RED_ALERT:
5781 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5785 case GS_STATE_CMD_BRIEF: {
5786 int team_num = 0; // team number used as index for which cmd brief to use.
5788 if (old_state == GS_STATE_OPTIONS_MENU) {
5792 main_hall_stop_music();
5793 main_hall_stop_ambient();
5795 if (Game_mode & GM_NORMAL) {
5796 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5797 // MWA: or from options or hotkey screens
5798 // JH: or if the command brief state already did this
5799 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5800 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5801 if ( !game_start_mission() ) // this should put us into a new state on failure!
5806 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5807 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5808 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5810 cmd_brief_init(team_num);
5816 case GS_STATE_SHIP_SELECT:
5820 case GS_STATE_WEAPON_SELECT:
5821 weapon_select_init();
5824 case GS_STATE_TEAM_SELECT:
5828 case GS_STATE_GAME_PAUSED:
5833 case GS_STATE_DEBUG_PAUSED:
5834 // game_stop_time();
5835 // os_set_title("FreeSpace - PAUSED");
5838 case GS_STATE_TRAINING_PAUSED:
5845 case GS_STATE_OPTIONS_MENU:
5847 options_menu_init();
5850 case GS_STATE_GAME_PLAY:
5851 // coming from the gameplay state or the main menu, we might need to load the mission
5852 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5853 if ( !game_start_mission() ) // this should put us into a new state.
5858 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5859 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5860 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5861 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5862 (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) ) {
5863 // JAS: Used to do all paging here.
5867 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5871 main_hall_stop_music();
5872 main_hall_stop_ambient();
5873 event_music_first_pattern(); // start the first pattern
5876 // special code that restores player ship selection and weapons loadout when doing a quick start
5877 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5878 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5879 wss_direct_restore_loadout();
5883 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5884 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5885 event_music_first_pattern(); // start the first pattern
5888 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5889 event_music_first_pattern(); // start the first pattern
5891 player_restore_target_and_weapon_link_prefs();
5893 Game_mode |= GM_IN_MISSION;
5896 // required to truely make mouse deltas zeroed in debug mouse code
5897 void mouse_force_pos(int x, int y);
5898 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5903 // only start time if in single player, or coming from multi wait state
5906 (Game_mode & GM_NORMAL) &&
5907 (old_state != GS_STATE_VIEW_CUTSCENES)
5909 (Game_mode & GM_MULTIPLAYER) && (
5910 (old_state == GS_STATE_MULTI_PAUSED) ||
5911 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5917 // when coming from the multi paused state, reset the timestamps
5918 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5919 multi_reset_timestamps();
5922 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5923 // initialize all object update details
5924 multi_oo_gameplay_init();
5927 // under certain circumstances, the server should reset the object update rate limiting stuff
5928 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5929 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5931 // reinitialize the rate limiting system for all clients
5932 multi_oo_rate_init_all();
5935 // multiplayer clients should always re-initialize their control info rate limiting system
5936 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5937 multi_oo_rate_init_all();
5941 if(Game_mode & GM_MULTIPLAYER){
5942 multi_ping_reset_players();
5945 Game_subspace_effect = 0;
5946 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5947 Game_subspace_effect = 1;
5948 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5949 game_start_subspace_ambient_sound();
5953 sound_env_set(&Game_sound_env);
5954 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5956 // clear multiplayer button info i
5957 extern button_info Multi_ship_status_bi;
5958 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5961 case GS_STATE_HUD_CONFIG:
5965 case GS_STATE_MULTI_JOIN_GAME:
5966 multi_join_clear_game_list();
5968 if (old_state != GS_STATE_OPTIONS_MENU) {
5969 multi_join_game_init();
5974 case GS_STATE_MULTI_HOST_SETUP:
5975 // don't reinitialize if we're coming back from the host options screen
5976 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5977 multi_create_game_init();
5982 case GS_STATE_MULTI_CLIENT_SETUP:
5983 if (old_state != GS_STATE_OPTIONS_MENU) {
5984 multi_game_client_setup_init();
5989 case GS_STATE_CONTROL_CONFIG:
5990 control_config_init();
5993 case GS_STATE_TECH_MENU:
5997 case GS_STATE_BARRACKS_MENU:
5998 if(old_state != GS_STATE_VIEW_MEDALS){
6003 case GS_STATE_MISSION_LOG_SCROLLBACK:
6004 hud_scrollback_init();
6007 case GS_STATE_DEATH_DIED:
6008 Player_died_time = timestamp(10);
6010 if(!(Game_mode & GM_MULTIPLAYER)){
6011 player_show_death_message();
6013 Game_mode |= GM_DEAD_DIED;
6016 case GS_STATE_DEATH_BLEW_UP:
6017 if ( !popupdead_is_active() ) {
6018 Player_ai->target_objnum = -1;
6021 // stop any local EMP effect
6024 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6025 Game_mode |= GM_DEAD_BLEW_UP;
6026 Show_viewing_from_self = 0;
6028 // timestamp how long we should wait before displaying the died popup
6029 if ( !popupdead_is_active() ) {
6030 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6034 case GS_STATE_GAMEPLAY_HELP:
6035 gameplay_help_init();
6038 case GS_STATE_CREDITS:
6039 main_hall_stop_music();
6040 main_hall_stop_ambient();
6044 case GS_STATE_VIEW_MEDALS:
6045 medal_main_init(Player);
6048 case GS_STATE_SHOW_GOALS:
6049 mission_show_goals_init();
6052 case GS_STATE_HOTKEY_SCREEN:
6053 mission_hotkey_init();
6056 case GS_STATE_MULTI_MISSION_SYNC:
6057 // if we're coming from the options screen, don't do any
6058 if(old_state == GS_STATE_OPTIONS_MENU){
6062 switch(Multi_sync_mode){
6063 case MULTI_SYNC_PRE_BRIEFING:
6064 // if moving from game forming to the team select state
6067 case MULTI_SYNC_POST_BRIEFING:
6068 // if moving from briefing into the mission itself
6071 // tell everyone that we're now loading data
6072 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6073 send_netplayer_update_packet();
6075 // JAS: Used to do all paging here!!!!
6077 Net_player->state = NETPLAYER_STATE_WAITING;
6078 send_netplayer_update_packet();
6080 Game_time_compression = F1_0;
6082 case MULTI_SYNC_INGAME:
6088 case GS_STATE_VIEW_CUTSCENES:
6089 cutscenes_screen_init();
6092 case GS_STATE_MULTI_STD_WAIT:
6093 multi_standalone_wait_init();
6096 case GS_STATE_STANDALONE_MAIN:
6097 // don't initialize if we're coming from one of these 2 states unless there are no
6098 // players left (reset situation)
6099 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6100 standalone_main_init();
6104 case GS_STATE_MULTI_PAUSED:
6108 case GS_STATE_INGAME_PRE_JOIN:
6109 multi_ingame_select_init();
6112 case GS_STATE_STANDALONE_POSTGAME:
6113 multi_standalone_postgame_init();
6116 case GS_STATE_INITIAL_PLAYER_SELECT:
6117 player_select_init();
6120 case GS_STATE_MULTI_START_GAME:
6121 multi_start_game_init();
6124 case GS_STATE_MULTI_HOST_OPTIONS:
6125 multi_host_options_init();
6128 case GS_STATE_END_OF_CAMPAIGN:
6129 mission_campaign_end_init();
6132 case GS_STATE_LOOP_BRIEF:
6139 // do stuff that may need to be done regardless of state
6140 void game_do_state_common(int state,int no_networking)
6142 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6143 snd_do_frame(); // update sound system
6144 event_music_do_frame(); // music needs to play across many states
6146 multi_log_process();
6148 if (no_networking) {
6152 // maybe do a multiplayer frame based on game mode and state type
6153 if (Game_mode & GM_MULTIPLAYER) {
6155 case GS_STATE_OPTIONS_MENU:
6156 case GS_STATE_GAMEPLAY_HELP:
6157 case GS_STATE_HOTKEY_SCREEN:
6158 case GS_STATE_HUD_CONFIG:
6159 case GS_STATE_CONTROL_CONFIG:
6160 case GS_STATE_MISSION_LOG_SCROLLBACK:
6161 case GS_STATE_SHOW_GOALS:
6162 case GS_STATE_VIEW_CUTSCENES:
6163 case GS_STATE_EVENT_DEBUG:
6164 multi_maybe_do_frame();
6168 game_do_networking();
6172 // Called once a frame.
6173 // You should never try to change the state
6174 // in here... if you think you need to, you probably really
6175 // need to post an event, not change the state.
6176 int Game_do_state_should_skip = 0;
6177 void game_do_state(int state)
6179 // always lets the do_state_common() function determine if the state should be skipped
6180 Game_do_state_should_skip = 0;
6182 // legal to set the should skip state anywhere in this function
6183 game_do_state_common(state); // do stuff that may need to be done regardless of state
6185 if(Game_do_state_should_skip){
6190 case GS_STATE_MAIN_MENU:
6191 game_set_frametime(GS_STATE_MAIN_MENU);
6192 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6195 main_hall_do(flFrametime);
6199 case GS_STATE_OPTIONS_MENU:
6200 game_set_frametime(GS_STATE_OPTIONS_MENU);
6201 options_menu_do_frame(flFrametime);
6204 case GS_STATE_BARRACKS_MENU:
6205 game_set_frametime(GS_STATE_BARRACKS_MENU);
6206 barracks_do_frame(flFrametime);
6209 case GS_STATE_TRAINING_MENU:
6210 game_set_frametime(GS_STATE_TRAINING_MENU);
6211 training_menu_do_frame(flFrametime);
6214 case GS_STATE_TECH_MENU:
6215 game_set_frametime(GS_STATE_TECH_MENU);
6216 techroom_do_frame(flFrametime);
6219 case GS_STATE_GAMEPLAY_HELP:
6220 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6221 gameplay_help_do_frame(flFrametime);
6224 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6228 case GS_STATE_GAME_PAUSED:
6232 case GS_STATE_DEBUG_PAUSED:
6234 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6239 case GS_STATE_TRAINING_PAUSED:
6240 game_training_pause_do();
6243 case GS_STATE_LOAD_MISSION_MENU:
6244 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6245 mission_load_menu_do();
6248 case GS_STATE_BRIEFING:
6249 game_set_frametime(GS_STATE_BRIEFING);
6250 brief_do_frame(flFrametime);
6253 case GS_STATE_DEBRIEF:
6254 game_set_frametime(GS_STATE_DEBRIEF);
6255 debrief_do_frame(flFrametime);
6258 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6259 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6260 multi_df_debrief_do();
6263 case GS_STATE_SHIP_SELECT:
6264 game_set_frametime(GS_STATE_SHIP_SELECT);
6265 ship_select_do(flFrametime);
6268 case GS_STATE_WEAPON_SELECT:
6269 game_set_frametime(GS_STATE_WEAPON_SELECT);
6270 weapon_select_do(flFrametime);
6273 case GS_STATE_MISSION_LOG_SCROLLBACK:
6274 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6275 hud_scrollback_do_frame(flFrametime);
6278 case GS_STATE_HUD_CONFIG:
6279 game_set_frametime(GS_STATE_HUD_CONFIG);
6280 hud_config_do_frame(flFrametime);
6283 case GS_STATE_MULTI_JOIN_GAME:
6284 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6285 multi_join_game_do_frame();
6288 case GS_STATE_MULTI_HOST_SETUP:
6289 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6290 multi_create_game_do();
6293 case GS_STATE_MULTI_CLIENT_SETUP:
6294 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6295 multi_game_client_setup_do_frame();
6298 case GS_STATE_CONTROL_CONFIG:
6299 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6300 control_config_do_frame(flFrametime);
6303 case GS_STATE_DEATH_DIED:
6307 case GS_STATE_DEATH_BLEW_UP:
6311 case GS_STATE_SIMULATOR_ROOM:
6312 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6313 sim_room_do_frame(flFrametime);
6316 case GS_STATE_CAMPAIGN_ROOM:
6317 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6318 campaign_room_do_frame(flFrametime);
6321 case GS_STATE_RED_ALERT:
6322 game_set_frametime(GS_STATE_RED_ALERT);
6323 red_alert_do_frame(flFrametime);
6326 case GS_STATE_CMD_BRIEF:
6327 game_set_frametime(GS_STATE_CMD_BRIEF);
6328 cmd_brief_do_frame(flFrametime);
6331 case GS_STATE_CREDITS:
6332 game_set_frametime(GS_STATE_CREDITS);
6333 credits_do_frame(flFrametime);
6336 case GS_STATE_VIEW_MEDALS:
6337 game_set_frametime(GS_STATE_VIEW_MEDALS);
6341 case GS_STATE_SHOW_GOALS:
6342 game_set_frametime(GS_STATE_SHOW_GOALS);
6343 mission_show_goals_do_frame(flFrametime);
6346 case GS_STATE_HOTKEY_SCREEN:
6347 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6348 mission_hotkey_do_frame(flFrametime);
6351 case GS_STATE_VIEW_CUTSCENES:
6352 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6353 cutscenes_screen_do_frame();
6356 case GS_STATE_MULTI_STD_WAIT:
6357 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6358 multi_standalone_wait_do();
6361 case GS_STATE_STANDALONE_MAIN:
6362 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6363 standalone_main_do();
6366 case GS_STATE_MULTI_PAUSED:
6367 game_set_frametime(GS_STATE_MULTI_PAUSED);
6371 case GS_STATE_TEAM_SELECT:
6372 game_set_frametime(GS_STATE_TEAM_SELECT);
6376 case GS_STATE_INGAME_PRE_JOIN:
6377 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6378 multi_ingame_select_do();
6381 case GS_STATE_EVENT_DEBUG:
6383 game_set_frametime(GS_STATE_EVENT_DEBUG);
6384 game_show_event_debug(flFrametime);
6388 case GS_STATE_STANDALONE_POSTGAME:
6389 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6390 multi_standalone_postgame_do();
6393 case GS_STATE_INITIAL_PLAYER_SELECT:
6394 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6398 case GS_STATE_MULTI_MISSION_SYNC:
6399 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6403 case GS_STATE_MULTI_START_GAME:
6404 game_set_frametime(GS_STATE_MULTI_START_GAME);
6405 multi_start_game_do();
6408 case GS_STATE_MULTI_HOST_OPTIONS:
6409 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6410 multi_host_options_do();
6413 case GS_STATE_END_OF_CAMPAIGN:
6414 mission_campaign_end_do();
6417 case GS_STATE_END_DEMO:
6418 game_set_frametime(GS_STATE_END_DEMO);
6419 end_demo_campaign_do();
6422 case GS_STATE_LOOP_BRIEF:
6423 game_set_frametime(GS_STATE_LOOP_BRIEF);
6427 } // end switch(gs_current_state)
6431 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6432 int game_do_ram_check(int ram_in_bytes)
6434 if ( ram_in_bytes < 30*1024*1024 ) {
6435 int allowed_to_run = 1;
6436 if ( ram_in_bytes < 25*1024*1024 ) {
6441 int Freespace_total_ram_MB;
6442 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6444 if ( allowed_to_run ) {
6446 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);
6450 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6451 if ( msgbox_rval == IDCANCEL ) {
6458 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);
6460 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6471 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6472 // If so, copy it over and remove the update directory.
6473 void game_maybe_update_launcher(char *exe_dir)
6476 char src_filename[MAX_PATH];
6477 char dest_filename[MAX_PATH];
6479 strcpy(src_filename, exe_dir);
6480 strcat(src_filename, NOX("\\update\\freespace.exe"));
6482 strcpy(dest_filename, exe_dir);
6483 strcat(dest_filename, NOX("\\freespace.exe"));
6485 // see if src_filename exists
6487 fp = fopen(src_filename, "rb");
6493 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6495 // copy updated freespace.exe to freespace exe dir
6496 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6497 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 );
6501 // delete the file in the update directory
6502 DeleteFile(src_filename);
6504 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6505 char update_dir[MAX_PATH];
6506 strcpy(update_dir, exe_dir);
6507 strcat(update_dir, NOX("\\update"));
6508 RemoveDirectory(update_dir);
6514 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6518 int sub_total_destroyed = 0;
6522 // get the total for all his children
6523 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6524 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6527 // find the # of faces for this _individual_ object
6528 total = submodel_get_num_polys(model_num, sm);
6529 if(strstr(pm->submodel[sm].name, "-destroyed")){
6530 sub_total_destroyed = total;
6534 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6537 *out_total += total + sub_total;
6538 *out_destroyed_total += sub_total_destroyed;
6541 #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);
6542 void game_spew_pof_info()
6544 char *pof_list[1000];
6547 int idx, model_num, i, j;
6549 int total, root_total, model_total, destroyed_total, counted;
6553 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6555 // spew info on all the pofs
6561 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6566 for(idx=0; idx<num_files; idx++, counted++){
6567 sprintf(str, "%s.pof", pof_list[idx]);
6568 model_num = model_load(str, 0, NULL);
6570 pm = model_get(model_num);
6572 // if we have a real model
6577 // go through and print all raw submodels
6578 cfputs("RAW\n", out);
6581 for (i=0; i<pm->n_models; i++) {
6582 total = submodel_get_num_polys(model_num, i);
6584 model_total += total;
6585 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6588 sprintf(str, "Model total %d\n", model_total);
6591 // now go through and do it by LOD
6592 cfputs("BY LOD\n\n", out);
6593 for(i=0; i<pm->n_detail_levels; i++){
6594 sprintf(str, "LOD %d\n", i);
6598 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6600 destroyed_total = 0;
6601 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6602 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6605 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6608 sprintf(str, "TOTAL: %d\n", total + root_total);
6610 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6612 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6615 cfputs("------------------------------------------------------------------------\n\n", out);
6619 if(counted >= MAX_POLYGON_MODELS - 5){
6632 game_spew_pof_info();
6635 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6640 // Don't let more than one instance of Freespace run.
6641 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6643 SetForegroundWindow(hwnd);
6648 // Find out how much RAM is on this machine
6651 ms.dwLength = sizeof(MEMORYSTATUS);
6652 GlobalMemoryStatus(&ms);
6653 Freespace_total_ram = ms.dwTotalPhys;
6655 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6659 if ( ms.dwTotalVirtual < 1024 ) {
6660 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6664 if (!vm_init(24*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 );
6669 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6671 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);
6681 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6682 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6683 seem worth bothering with.
6687 lResult = RegOpenKeyEx(
6688 HKEY_LOCAL_MACHINE, // Where it is
6689 "Software\\Microsoft\\DirectX", // name of key
6690 NULL, // DWORD reserved
6691 KEY_QUERY_VALUE, // Allows all changes
6692 &hKey // Location to store key
6695 if (lResult == ERROR_SUCCESS) {
6697 DWORD dwType, dwLen;
6700 lResult = RegQueryValueEx(
6701 hKey, // Handle to key
6702 "Version", // The values name
6703 NULL, // DWORD reserved
6704 &dwType, // What kind it is
6705 (ubyte *) version, // value to set
6706 &dwLen // How many bytes to set
6709 if (lResult == ERROR_SUCCESS) {
6710 dx_version = atoi(strstr(version, ".") + 1);
6714 DWORD dwType, dwLen;
6717 lResult = RegQueryValueEx(
6718 hKey, // Handle to key
6719 "InstalledVersion", // The values name
6720 NULL, // DWORD reserved
6721 &dwType, // What kind it is
6722 (ubyte *) &val, // value to set
6723 &dwLen // How many bytes to set
6726 if (lResult == ERROR_SUCCESS) {
6734 if (dx_version < 3) {
6735 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6736 "latest version of DirectX at:\n\n"
6737 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6739 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6740 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6745 //=====================================================
6746 // Make sure we're running in the right directory.
6750 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6751 char *p = exe_dir + strlen(exe_dir);
6753 // chop off the filename
6754 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6760 if ( strlen(exe_dir) > 0 ) {
6761 SetCurrentDirectory(exe_dir);
6764 // check for updated freespace.exe
6765 game_maybe_update_launcher(exe_dir);
6773 extern void windebug_memwatch_init();
6774 windebug_memwatch_init();
6778 parse_cmdline(szCmdLine);
6780 #ifdef STANDALONE_ONLY_BUILD
6782 nprintf(("Network", "Standalone running"));
6785 nprintf(("Network", "Standalone running"));
6793 // maybe spew pof stuff
6794 if(Cmdline_spew_pof_info){
6795 game_spew_pof_info();
6800 // non-demo, non-standalone, play the intro movie
6805 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) ){
6807 #if defined(OEM_BUILD)
6808 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6810 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6811 #endif // defined(OEM_BUILD)
6816 if ( !Is_standalone ) {
6818 // release -- movies always play
6821 // 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
6823 // movie_play( NOX("intro.mve"), 0 );
6825 // debug version, movie will only play with -showmovies
6826 #elif !defined(NDEBUG)
6829 // movie_play( NOX("intro.mve"), 0);
6832 if ( Cmdline_show_movies )
6833 movie_play( NOX("intro.mve"), 0 );
6842 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6844 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6848 // only important for non THREADED mode
6851 state = gameseq_process_events();
6852 if ( state == GS_STATE_QUIT_GAME ){
6859 demo_upsell_show_screens();
6861 #elif defined(OEM_BUILD)
6862 // show upsell screens on exit
6863 oem_upsell_show_screens();
6870 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6876 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6878 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6880 // Do nothing here - RecordExceptionInfo() has already done
6881 // everything that is needed. Actually this code won't even
6882 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6883 // the __except clause.
6889 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6890 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6894 // launcher the fslauncher program on exit
6895 void game_launch_launcher_on_exit()
6899 PROCESS_INFORMATION pi;
6900 char cmd_line[2048];
6901 char original_path[1024] = "";
6903 memset( &si, 0, sizeof(STARTUPINFO) );
6907 _getcwd(original_path, 1023);
6909 // set up command line
6910 strcpy(cmd_line, original_path);
6911 strcat(cmd_line, "\\");
6912 strcat(cmd_line, LAUNCHER_FNAME);
6913 strcat(cmd_line, " -straight_to_update");
6915 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6916 cmd_line, // pointer to command line string
6917 NULL, // pointer to process security attributes
6918 NULL, // pointer to thread security attributes
6919 FALSE, // handle inheritance flag
6920 CREATE_DEFAULT_ERROR_MODE, // creation flags
6921 NULL, // pointer to new environment block
6922 NULL, // pointer to current directory name
6923 &si, // pointer to STARTUPINFO
6924 &pi // pointer to PROCESS_INFORMATION
6926 // to eliminate build warnings
6936 // This function is called when FreeSpace terminates normally.
6938 void game_shutdown(void)
6944 // don't ever flip a page on the standalone!
6945 if(!(Game_mode & GM_STANDALONE_SERVER)){
6951 // if the player has left the "player select" screen and quit the game without actually choosing
6952 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6953 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6957 // load up common multiplayer icons
6958 multi_unload_common_icons();
6960 shockwave_close(); // release any memory used by shockwave system
6961 fireball_close(); // free fireball system
6962 ship_close(); // free any memory that was allocated for the ships
6963 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6964 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6965 bm_unload_all(); // free bitmaps
6966 mission_campaign_close(); // close out the campaign stuff
6967 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6969 #ifdef MULTI_USE_LAG
6973 // the menu close functions will unload the bitmaps if they were displayed during the game
6974 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6977 training_menu_close();
6980 extern void joy_close();
6983 audiostream_close();
6985 event_music_close();
6989 // HACKITY HACK HACK
6990 // if this flag is set, we should be firing up the launcher when exiting freespace
6991 extern int Multi_update_fireup_launcher_on_exit;
6992 if(Multi_update_fireup_launcher_on_exit){
6993 game_launch_launcher_on_exit();
6997 // game_stop_looped_sounds()
6999 // This function will call the appropriate stop looped sound functions for those
7000 // modules which use looping sounds. It is not enough just to stop a looping sound
7001 // at the DirectSound level, the game is keeping track of looping sounds, and this
7002 // function is used to inform the game that looping sounds are being halted.
7004 void game_stop_looped_sounds()
7006 hud_stop_looped_locking_sounds();
7007 hud_stop_looped_engine_sounds();
7008 afterburner_stop_sounds();
7009 player_stop_looped_sounds();
7010 obj_snd_stop_all(); // stop all object-linked persistant sounds
7011 game_stop_subspace_ambient_sound();
7012 snd_stop(Radar_static_looping);
7013 Radar_static_looping = -1;
7014 snd_stop(Target_static_looping);
7015 shipfx_stop_engine_wash_sound();
7016 Target_static_looping = -1;
7019 //////////////////////////////////////////////////////////////////////////
7021 // Code for supporting an animating mouse pointer
7024 //////////////////////////////////////////////////////////////////////////
7026 typedef struct animating_obj
7035 static animating_obj Animating_mouse;
7037 // ----------------------------------------------------------------------------
7038 // init_animating_pointer()
7040 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7041 // gets properly initialized
7043 void init_animating_pointer()
7045 Animating_mouse.first_frame = -1;
7046 Animating_mouse.num_frames = 0;
7047 Animating_mouse.current_frame = -1;
7048 Animating_mouse.time = 0.0f;
7049 Animating_mouse.elapsed_time = 0.0f;
7052 // ----------------------------------------------------------------------------
7053 // load_animating_pointer()
7055 // Called at game init to load in the frames for the animating mouse pointer
7057 // input: filename => filename of animation file that holds the animation
7059 void load_animating_pointer(char *filename, int dx, int dy)
7064 init_animating_pointer();
7066 am = &Animating_mouse;
7067 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7068 if ( am->first_frame == -1 )
7069 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7070 am->current_frame = 0;
7071 am->time = am->num_frames / i2fl(fps);
7074 // ----------------------------------------------------------------------------
7075 // unload_animating_pointer()
7077 // Called at game shutdown to free the memory used to store the animation frames
7079 void unload_animating_pointer()
7084 am = &Animating_mouse;
7085 for ( i = 0; i < am->num_frames; i++ ) {
7086 Assert( (am->first_frame+i) >= 0 );
7087 bm_release(am->first_frame + i);
7090 am->first_frame = -1;
7092 am->current_frame = -1;
7095 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7096 void game_render_mouse(float frametime)
7101 // if animating cursor exists, play the next frame
7102 am = &Animating_mouse;
7103 if ( am->first_frame != -1 ) {
7104 mouse_get_pos(&mx, &my);
7105 am->elapsed_time += frametime;
7106 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7107 if ( am->current_frame >= am->num_frames ) {
7108 am->current_frame = 0;
7109 am->elapsed_time = 0.0f;
7111 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7115 // ----------------------------------------------------------------------------
7116 // game_maybe_draw_mouse()
7118 // determines whether to draw the mouse pointer at all, and what frame of
7119 // animation to use if the mouse is animating
7121 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7123 // input: frametime => elapsed frame time in seconds since last call
7125 void game_maybe_draw_mouse(float frametime)
7129 game_state = gameseq_get_state();
7131 switch ( game_state ) {
7132 case GS_STATE_GAME_PAUSED:
7133 // case GS_STATE_MULTI_PAUSED:
7134 case GS_STATE_GAME_PLAY:
7135 case GS_STATE_DEATH_DIED:
7136 case GS_STATE_DEATH_BLEW_UP:
7137 if ( popup_active() || popupdead_is_active() ) {
7149 if ( !Mouse_hidden )
7150 game_render_mouse(frametime);
7154 void game_do_training_checks()
7158 waypoint_list *wplp;
7160 if (Training_context & TRAINING_CONTEXT_SPEED) {
7161 s = (int) Player_obj->phys_info.fspeed;
7162 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7163 if (!Training_context_speed_set) {
7164 Training_context_speed_set = 1;
7165 Training_context_speed_timestamp = timestamp();
7169 Training_context_speed_set = 0;
7172 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7173 wplp = &Waypoint_lists[Training_context_path];
7174 if (wplp->count > Training_context_goal_waypoint) {
7175 i = Training_context_goal_waypoint;
7177 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7178 if (d <= Training_context_distance) {
7179 Training_context_at_waypoint = i;
7180 if (Training_context_goal_waypoint == i) {
7181 Training_context_goal_waypoint++;
7182 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7189 if (i == wplp->count)
7192 } while (i != Training_context_goal_waypoint);
7196 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7197 Players_target = Player_ai->target_objnum;
7198 Players_targeted_subsys = Player_ai->targeted_subsys;
7199 Players_target_timestamp = timestamp();
7203 /////////// Following is for event debug view screen
7207 #define EVENT_DEBUG_MAX 5000
7208 #define EVENT_DEBUG_EVENT 0x8000
7210 int Event_debug_index[EVENT_DEBUG_MAX];
7213 void game_add_event_debug_index(int n, int indent)
7215 if (ED_count < EVENT_DEBUG_MAX)
7216 Event_debug_index[ED_count++] = n | (indent << 16);
7219 void game_add_event_debug_sexp(int n, int indent)
7224 if (Sexp_nodes[n].first >= 0) {
7225 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7226 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7230 game_add_event_debug_index(n, indent);
7231 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7232 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7234 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7237 void game_event_debug_init()
7242 for (e=0; e<Num_mission_events; e++) {
7243 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7244 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7248 void game_show_event_debug(float frametime)
7252 int font_height, font_width;
7254 static int scroll_offset = 0;
7256 k = game_check_key();
7262 if (scroll_offset < 0)
7272 scroll_offset -= 20;
7273 if (scroll_offset < 0)
7278 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7282 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7288 gr_set_color_fast(&Color_bright);
7290 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7292 gr_set_color_fast(&Color_normal);
7294 gr_get_string_size(&font_width, &font_height, NOX("test"));
7295 y_max = gr_screen.max_h - font_height - 5;
7299 while (k < ED_count) {
7300 if (y_index > y_max)
7303 z = Event_debug_index[k];
7304 if (z & EVENT_DEBUG_EVENT) {
7306 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7307 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7308 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7309 Mission_events[z].repeat_count, Mission_events[z].interval);
7317 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7318 switch (Sexp_nodes[z & 0x7fff].value) {
7320 strcat(buf, NOX(" (True)"));
7324 strcat(buf, NOX(" (False)"));
7327 case SEXP_KNOWN_TRUE:
7328 strcat(buf, NOX(" (Always true)"));
7331 case SEXP_KNOWN_FALSE:
7332 strcat(buf, NOX(" (Always false)"));
7335 case SEXP_CANT_EVAL:
7336 strcat(buf, NOX(" (Can't eval)"));
7340 case SEXP_NAN_FOREVER:
7341 strcat(buf, NOX(" (Not a number)"));
7346 gr_printf(10, y_index, buf);
7347 y_index += font_height;
7360 extern int Tmap_npixels;
7362 int Tmap_num_too_big = 0;
7363 int Num_models_needing_splitting = 0;
7365 void Time_model( int modelnum )
7367 // mprintf(( "Timing ship '%s'\n", si->name ));
7369 vector eye_pos, model_pos;
7370 matrix eye_orient, model_orient;
7372 polymodel *pm = model_get( modelnum );
7374 int l = strlen(pm->filename);
7376 if ( (l == '/') || (l=='\\') || (l==':')) {
7382 char *pof_file = &pm->filename[l];
7384 int model_needs_splitting = 0;
7386 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7388 for (i=0; i<pm->n_textures; i++ ) {
7389 char filename[1024];
7392 int bmp_num = pm->original_textures[i];
7393 if ( bmp_num > -1 ) {
7394 bm_get_palette(pm->original_textures[i], pal, filename );
7396 bm_get_info( pm->original_textures[i],&w, &h );
7399 if ( (w > 512) || (h > 512) ) {
7400 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7402 model_needs_splitting++;
7405 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7409 if ( model_needs_splitting ) {
7410 Num_models_needing_splitting++;
7412 eye_orient = model_orient = vmd_identity_matrix;
7413 eye_pos = model_pos = vmd_zero_vector;
7415 eye_pos.z = -pm->rad*2.0f;
7417 vector eye_to_model;
7419 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7420 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7422 fix t1 = timer_get_fixed_seconds();
7425 ta.p = ta.b = ta.h = 0.0f;
7430 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7432 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7434 modelstats_num_polys = modelstats_num_verts = 0;
7436 while( ta.h < PI2 ) {
7439 vm_angles_2_matrix(&m1, &ta );
7440 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7447 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7449 model_clear_instance( modelnum );
7450 model_set_detail_level(0); // use highest detail level
7451 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7459 int k = key_inkey();
7460 if ( k == KEY_ESC ) {
7465 fix t2 = timer_get_fixed_seconds();
7467 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7468 //bitmaps_used_this_frame /= framecount;
7470 modelstats_num_polys /= framecount;
7471 modelstats_num_verts /= framecount;
7473 Tmap_npixels /=framecount;
7476 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7477 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 );
7478 // 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 );
7484 int Time_models = 0;
7485 DCF_BOOL( time_models, Time_models );
7487 void Do_model_timings_test()
7491 if ( !Time_models ) return;
7493 mprintf(( "Timing models!\n" ));
7497 ubyte model_used[MAX_POLYGON_MODELS];
7498 int model_id[MAX_POLYGON_MODELS];
7499 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7504 for (i=0; i<Num_ship_types; i++ ) {
7505 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7507 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7508 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7511 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7512 if ( !Texture_fp ) return;
7514 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7515 if ( !Time_fp ) return;
7517 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7518 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7520 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7521 if ( model_used[i] ) {
7522 Time_model( model_id[i] );
7526 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7527 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7536 // Call this function when you want to inform the player that a feature is not
7537 // enabled in the DEMO version of FreSpace
7538 void game_feature_not_in_demo_popup()
7540 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7543 // format the specified time (fixed point) into a nice string
7544 void game_format_time(fix m_time,char *time_str)
7547 int hours,minutes,seconds;
7550 mtime = f2fl(m_time);
7552 // get the hours, minutes and seconds
7553 hours = (int)(mtime / 3600.0f);
7555 mtime -= (3600.0f * (float)hours);
7557 seconds = (int)mtime%60;
7558 minutes = (int)mtime/60;
7560 // print the hour if necessary
7562 sprintf(time_str,XSTR( "%d:", 201),hours);
7563 // if there are less than 10 minutes, print a leading 0
7565 strcpy(tmp,NOX("0"));
7566 strcat(time_str,tmp);
7570 // print the minutes
7572 sprintf(tmp,XSTR( "%d:", 201),minutes);
7573 strcat(time_str,tmp);
7575 sprintf(time_str,XSTR( "%d:", 201),minutes);
7578 // print the seconds
7580 strcpy(tmp,NOX("0"));
7581 strcat(time_str,tmp);
7583 sprintf(tmp,"%d",seconds);
7584 strcat(time_str,tmp);
7587 // Stuff version string in *str.
7588 void get_version_string(char *str)
7591 if ( FS_VERSION_BUILD == 0 ) {
7592 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7594 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7597 #if defined (FS2_DEMO)
7599 #elif defined (OEM_BUILD)
7600 strcat(str, " (OEM)");
7606 char myname[_MAX_PATH];
7607 int namelen, major, minor, build, waste;
7608 unsigned int buf_size;
7614 // Find my EXE file name
7615 hMod = GetModuleHandle(NULL);
7616 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7618 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7619 infop = (char *)malloc(version_size);
7620 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7622 // get the product version
7623 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7624 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7626 sprintf(str,"Dv%d.%02d",major, minor);
7628 sprintf(str,"v%d.%02d",major, minor);
7633 void get_version_string_short(char *str)
7635 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7638 // ----------------------------------------------------------------
7640 // OEM UPSELL SCREENS BEGIN
7642 // ----------------------------------------------------------------
7643 #if defined(OEM_BUILD)
7645 #define NUM_OEM_UPSELL_SCREENS 3
7646 #define OEM_UPSELL_SCREEN_DELAY 10000
7648 static int Oem_upsell_bitmaps_loaded = 0;
7649 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7650 static int Oem_upsell_screen_number = 0;
7651 static int Oem_upsell_show_next_bitmap_time;
7654 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7667 static int Oem_normal_cursor = -1;
7668 static int Oem_web_cursor = -1;
7669 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7670 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7672 void oem_upsell_next_screen()
7674 Oem_upsell_screen_number++;
7675 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7676 // extra long delay, mouse shown on last upsell
7677 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7681 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7685 void oem_upsell_load_bitmaps()
7689 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7690 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7694 void oem_upsell_unload_bitmaps()
7698 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7699 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7700 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7705 Oem_upsell_bitmaps_loaded = 0;
7708 // clickable hotspot on 3rd OEM upsell screen
7709 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7711 28, 350, 287, 96 // x, y, w, h
7714 45, 561, 460, 152 // x, y, w, h
7718 void oem_upsell_show_screens()
7720 int current_time, k;
7723 if ( !Oem_upsell_bitmaps_loaded ) {
7724 oem_upsell_load_bitmaps();
7725 Oem_upsell_bitmaps_loaded = 1;
7728 // may use upsell screens more than once
7729 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7730 Oem_upsell_screen_number = 0;
7736 int nframes; // used to pass, not really needed (should be 1)
7737 Oem_normal_cursor = gr_get_cursor_bitmap();
7738 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7739 Assert(Oem_web_cursor >= 0);
7740 if (Oem_web_cursor < 0) {
7741 Oem_web_cursor = Oem_normal_cursor;
7746 //oem_reset_trailer_timer();
7748 current_time = timer_get_milliseconds();
7753 // advance screen on keypress or timeout
7754 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7755 oem_upsell_next_screen();
7758 // check if we are done
7759 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7760 Oem_upsell_screen_number--;
7763 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7768 // show me the upsell
7769 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7770 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7774 // if this is the 3rd upsell, make it clickable, d00d
7775 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7777 int button_state = mouse_get_pos(&mx, &my);
7778 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])
7779 && (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]) )
7782 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7785 if (button_state & MOUSE_LEFT_BUTTON) {
7787 multi_pxo_url(OEM_UPSELL_URL);
7791 // switch cursor back to normal one
7792 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7797 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7807 oem_upsell_unload_bitmaps();
7809 // switch cursor back to normal one
7810 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7814 #endif // defined(OEM_BUILD)
7815 // ----------------------------------------------------------------
7817 // OEM UPSELL SCREENS END
7819 // ----------------------------------------------------------------
7823 // ----------------------------------------------------------------
7825 // DEMO UPSELL SCREENS BEGIN
7827 // ----------------------------------------------------------------
7831 //#define NUM_DEMO_UPSELL_SCREENS 4
7833 #define NUM_DEMO_UPSELL_SCREENS 2
7834 #define DEMO_UPSELL_SCREEN_DELAY 3000
7836 static int Demo_upsell_bitmaps_loaded = 0;
7837 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7838 static int Demo_upsell_screen_number = 0;
7839 static int Demo_upsell_show_next_bitmap_time;
7842 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7855 void demo_upsell_next_screen()
7857 Demo_upsell_screen_number++;
7858 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7859 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7861 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7865 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7866 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7867 #ifndef HARDWARE_ONLY
7868 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7875 void demo_upsell_load_bitmaps()
7879 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7880 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7884 void demo_upsell_unload_bitmaps()
7888 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7889 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7890 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7895 Demo_upsell_bitmaps_loaded = 0;
7898 void demo_upsell_show_screens()
7900 int current_time, k;
7903 if ( !Demo_upsell_bitmaps_loaded ) {
7904 demo_upsell_load_bitmaps();
7905 Demo_upsell_bitmaps_loaded = 1;
7908 // may use upsell screens more than once
7909 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7910 Demo_upsell_screen_number = 0;
7917 demo_reset_trailer_timer();
7919 current_time = timer_get_milliseconds();
7926 // don't time out, wait for keypress
7928 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7929 demo_upsell_next_screen();
7934 demo_upsell_next_screen();
7937 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7938 Demo_upsell_screen_number--;
7941 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7946 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7947 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7952 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7962 demo_upsell_unload_bitmaps();
7967 // ----------------------------------------------------------------
7969 // DEMO UPSELL SCREENS END
7971 // ----------------------------------------------------------------
7974 // ----------------------------------------------------------------
7976 // Subspace Ambient Sound START
7978 // ----------------------------------------------------------------
7980 static int Subspace_ambient_left_channel = -1;
7981 static int Subspace_ambient_right_channel = -1;
7984 void game_start_subspace_ambient_sound()
7986 if ( Subspace_ambient_left_channel < 0 ) {
7987 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7990 if ( Subspace_ambient_right_channel < 0 ) {
7991 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7995 void game_stop_subspace_ambient_sound()
7997 if ( Subspace_ambient_left_channel >= 0 ) {
7998 snd_stop(Subspace_ambient_left_channel);
7999 Subspace_ambient_left_channel = -1;
8002 if ( Subspace_ambient_right_channel >= 0 ) {
8003 snd_stop(Subspace_ambient_right_channel);
8004 Subspace_ambient_right_channel = -1;
8008 // ----------------------------------------------------------------
8010 // Subspace Ambient Sound END
8012 // ----------------------------------------------------------------
8014 // ----------------------------------------------------------------
8016 // CDROM detection code START
8018 // ----------------------------------------------------------------
8020 #define CD_SIZE_72_MINUTE_MAX (697000000)
8022 uint game_get_cd_used_space(char *path)
8026 char use_path[512] = "";
8027 char sub_path[512] = "";
8028 WIN32_FIND_DATA find;
8031 // recurse through all files and directories
8032 strcpy(use_path, path);
8033 strcat(use_path, "*.*");
8034 find_handle = FindFirstFile(use_path, &find);
8037 if(find_handle == INVALID_HANDLE_VALUE){
8043 // subdirectory. make sure to ignore . and ..
8044 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8046 strcpy(sub_path, path);
8047 strcat(sub_path, find.cFileName);
8048 strcat(sub_path, "\\");
8049 total += game_get_cd_used_space(sub_path);
8051 total += (uint)find.nFileSizeLow;
8053 } while(FindNextFile(find_handle, &find));
8056 FindClose(find_handle);
8068 // if volume_name is non-null, the CD name must match that
8069 int find_freespace_cd(char *volume_name)
8072 char oldpath[MAX_PATH];
8076 int volume_match = 0;
8080 GetCurrentDirectory(MAX_PATH, oldpath);
8082 for (i = 0; i < 26; i++)
8088 path[0] = (char)('A'+i);
8089 if (GetDriveType(path) == DRIVE_CDROM) {
8091 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8092 nprintf(("CD", "CD volume: %s\n", volume));
8094 // check for any CD volume
8095 int volume1_present = 0;
8096 int volume2_present = 0;
8097 int volume3_present = 0;
8099 char full_check[512] = "";
8101 // look for setup.exe
8102 strcpy(full_check, path);
8103 strcat(full_check, "setup.exe");
8104 find_handle = _findfirst(full_check, &find);
8105 if(find_handle != -1){
8106 volume1_present = 1;
8107 _findclose(find_handle);
8110 // look for intro.mve
8111 strcpy(full_check, path);
8112 strcat(full_check, "intro.mve");
8113 find_handle = _findfirst(full_check, &find);
8114 if(find_handle != -1){
8115 volume2_present = 1;
8116 _findclose(find_handle);
8119 // look for endpart1.mve
8120 strcpy(full_check, path);
8121 strcat(full_check, "endpart1.mve");
8122 find_handle = _findfirst(full_check, &find);
8123 if(find_handle != -1){
8124 volume3_present = 1;
8125 _findclose(find_handle);
8128 // see if we have the specific CD we're looking for
8129 if ( volume_name ) {
8131 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8135 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8139 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8143 if ( volume1_present || volume2_present || volume3_present ) {
8148 // 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
8149 if ( volume_match ){
8151 // 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
8152 if(volume2_present || volume3_present) {
8153 // first step - check to make sure its a cdrom
8154 if(GetDriveType(path) != DRIVE_CDROM){
8158 #if !defined(OEM_BUILD)
8159 // oem not on 80 min cds, so dont check tha size
8161 uint used_space = game_get_cd_used_space(path);
8162 if(used_space < CD_SIZE_72_MINUTE_MAX){
8165 #endif // !defined(OEM_BUILD)
8173 #endif // RELEASE_REAL
8179 SetCurrentDirectory(oldpath);
8188 int set_cdrom_path(int drive_num)
8192 if (drive_num < 0) { //no CD
8194 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8197 strcpy(Game_CDROM_dir,""); //set directory
8201 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8217 i = find_freespace_cd();
8219 rval = set_cdrom_path(i);
8223 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8225 nprintf(("CD", "FreeSpace CD not found\n"));
8233 int Last_cd_label_found = 0;
8234 char Last_cd_label[256];
8236 int game_cd_changed()
8243 if ( strlen(Game_CDROM_dir) == 0 ) {
8247 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8249 if ( found != Last_cd_label_found ) {
8250 Last_cd_label_found = found;
8252 mprintf(( "CD '%s' was inserted\n", label ));
8255 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8259 if ( Last_cd_label_found ) {
8260 if ( !stricmp( Last_cd_label, label )) {
8261 //mprintf(( "CD didn't change\n" ));
8263 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8267 // none found before, none found now.
8268 //mprintf(( "still no CD...\n" ));
8272 Last_cd_label_found = found;
8274 strcpy( Last_cd_label, label );
8276 strcpy( Last_cd_label, "" );
8285 // check if _any_ FreeSpace2 CDs are in the drive
8286 // return: 1 => CD now in drive
8287 // 0 => Could not find CD, they refuse to put it in the drive
8288 int game_do_cd_check(char *volume_name)
8290 #if !defined(GAME_CD_CHECK)
8296 int num_attempts = 0;
8297 int refresh_files = 0;
8299 int path_set_ok, popup_rval;
8301 cd_drive_num = find_freespace_cd(volume_name);
8302 path_set_ok = set_cdrom_path(cd_drive_num);
8303 if ( path_set_ok ) {
8305 if ( refresh_files ) {
8317 // no CD found, so prompt user
8318 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8320 if ( popup_rval != 1 ) {
8325 if ( num_attempts++ > 5 ) {
8336 // check if _any_ FreeSpace2 CDs are in the drive
8337 // return: 1 => CD now in drive
8338 // 0 => Could not find CD, they refuse to put it in the drive
8339 int game_do_cd_check_specific(char *volume_name, int cdnum)
8344 int num_attempts = 0;
8345 int refresh_files = 0;
8347 int path_set_ok, popup_rval;
8349 cd_drive_num = find_freespace_cd(volume_name);
8350 path_set_ok = set_cdrom_path(cd_drive_num);
8351 if ( path_set_ok ) {
8353 if ( refresh_files ) {
8364 // no CD found, so prompt user
8365 #if defined(DVD_MESSAGE_HACK)
8366 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8368 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8371 if ( popup_rval != 1 ) {
8376 if ( num_attempts++ > 5 ) {
8386 // only need to do this in RELEASE_REAL
8387 int game_do_cd_mission_check(char *filename)
8393 fs_builtin_mission *m = game_find_builtin_mission(filename);
8395 // check for changed CD
8396 if(game_cd_changed()){
8401 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8405 // not builtin, so do a general check (any FS2 CD will do)
8407 return game_do_cd_check();
8410 // does not have any CD requirement, do a general check
8411 if(strlen(m->cd_volume) <= 0){
8412 return game_do_cd_check();
8416 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8418 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8420 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8423 return game_do_cd_check();
8426 // did we find the cd?
8427 if(find_freespace_cd(m->cd_volume) >= 0){
8431 // make sure the volume exists
8432 int num_attempts = 0;
8433 int refresh_files = 0;
8435 int path_set_ok, popup_rval;
8437 cd_drive_num = find_freespace_cd(m->cd_volume);
8438 path_set_ok = set_cdrom_path(cd_drive_num);
8439 if ( path_set_ok ) {
8441 if ( refresh_files ) {
8448 // no CD found, so prompt user
8449 #if defined(DVD_MESSAGE_HACK)
8450 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8452 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8456 if ( popup_rval != 1 ) {
8461 if ( num_attempts++ > 5 ) {
8473 // ----------------------------------------------------------------
8475 // CDROM detection code END
8477 // ----------------------------------------------------------------
8479 // ----------------------------------------------------------------
8480 // SHIPS TBL VERIFICATION STUFF
8483 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8484 #define NUM_SHIPS_TBL_CHECKSUMS 1
8486 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8487 -463907578, // US - beta 1
8488 1696074201, // FS2 demo
8491 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8492 // -1022810006, // 1.0 FULL
8493 -1254285366 // 1.2 FULL (German)
8496 void verify_ships_tbl()
8500 Game_ships_tbl_valid = 1;
8506 // detect if the packfile exists
8507 CFILE *detect = cfopen("ships.tbl", "rb");
8508 Game_ships_tbl_valid = 0;
8512 Game_ships_tbl_valid = 0;
8516 // get the long checksum of the file
8518 cfseek(detect, 0, SEEK_SET);
8519 cf_chksum_long(detect, &file_checksum);
8523 // now compare the checksum/filesize against known #'s
8524 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8525 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8526 Game_ships_tbl_valid = 1;
8533 DCF(shipspew, "display the checksum for the current ships.tbl")
8536 CFILE *detect = cfopen("ships.tbl", "rb");
8537 // get the long checksum of the file
8539 cfseek(detect, 0, SEEK_SET);
8540 cf_chksum_long(detect, &file_checksum);
8543 dc_printf("%d", file_checksum);
8546 // ----------------------------------------------------------------
8547 // WEAPONS TBL VERIFICATION STUFF
8550 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8551 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8553 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8554 141718090, // US - beta 1
8555 -266420030, // demo 1
8558 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8559 // 399297860, // 1.0 FULL
8560 -553984927 // 1.2 FULL (german)
8563 void verify_weapons_tbl()
8567 Game_weapons_tbl_valid = 1;
8573 // detect if the packfile exists
8574 CFILE *detect = cfopen("weapons.tbl", "rb");
8575 Game_weapons_tbl_valid = 0;
8579 Game_weapons_tbl_valid = 0;
8583 // get the long checksum of the file
8585 cfseek(detect, 0, SEEK_SET);
8586 cf_chksum_long(detect, &file_checksum);
8590 // now compare the checksum/filesize against known #'s
8591 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8592 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8593 Game_weapons_tbl_valid = 1;
8600 DCF(wepspew, "display the checksum for the current weapons.tbl")
8603 CFILE *detect = cfopen("weapons.tbl", "rb");
8604 // get the long checksum of the file
8606 cfseek(detect, 0, SEEK_SET);
8607 cf_chksum_long(detect, &file_checksum);
8610 dc_printf("%d", file_checksum);
8613 // if the game is running using hacked data
8614 int game_hacked_data()
8617 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8625 void display_title_screen()
8627 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8628 ///int title_bitmap;
8631 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8632 if (title_bitmap == -1) {
8637 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8638 extern void d3d_start_frame();
8643 gr_set_bitmap(title_bitmap);
8649 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8650 extern void d3d_stop_frame();
8657 bm_unload(title_bitmap);
8658 #endif // FS2_DEMO || OEM_BUILD
8661 // return true if the game is running with "low memory", which is less than 48MB
8662 bool game_using_low_mem()
8664 if (Use_low_mem == 0) {