2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.5 2002/05/28 04:07:28 theoddone33
11 * New graphics stubbing arrangement
13 * Revision 1.4 2002/05/27 22:46:52 theoddone33
14 * Remove more undefined symbols
16 * Revision 1.3 2002/05/26 23:31:18 relnev
17 * added a few files that needed to be compiled
19 * freespace.cpp: now compiles
21 * Revision 1.2 2002/05/07 03:16:44 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 201 6/16/00 3:15p Jefff
29 * sim of the year dvd version changes, a few german soty localization
32 * 200 11/03/99 11:06a Jefff
35 * 199 10/26/99 5:07p Jamest
36 * fixed jeffs dumb debug code
38 * 198 10/25/99 5:53p Jefff
39 * call control_config_common_init() on startup
41 * 197 10/14/99 10:18a Daveb
42 * Fixed incorrect CD checking problem on standalone server.
44 * 196 10/13/99 9:22a Daveb
45 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
46 * related to movies. Fixed launcher spawning from PXO screen.
48 * 195 10/06/99 11:05a Jefff
49 * new oem upsell 3 hotspot coords
51 * 194 10/06/99 10:31a Jefff
54 * 193 10/01/99 9:10a Daveb
57 * 192 9/15/99 4:57a Dave
58 * Updated ships.tbl checksum
60 * 191 9/15/99 3:58a Dave
61 * Removed framerate warning at all times.
63 * 190 9/15/99 3:16a Dave
64 * Remove mt-011.fs2 from the builtin mission list.
66 * 189 9/15/99 1:45a Dave
67 * Don't init joystick on standalone. Fixed campaign mode on standalone.
68 * Fixed no-score-report problem in TvT
70 * 188 9/14/99 6:08a Dave
71 * Updated (final) single, multi, and campaign list.
73 * 187 9/14/99 3:26a Dave
74 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
75 * respawn-too-early problem. Made a few crash points safe.
77 * 186 9/13/99 4:52p Dave
80 * 185 9/12/99 8:09p Dave
81 * Fixed problem where skip-training button would cause mission messages
82 * not to get paged out for the current mission.
84 * 184 9/10/99 11:53a Dave
85 * Shutdown graphics before sound to eliminate apparent lockups when
86 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
88 * 183 9/09/99 11:40p Dave
89 * Handle an Assert() in beam code. Added supernova sounds. Play the right
90 * 2 end movies properly, based upon what the player did in the mission.
92 * 182 9/08/99 10:29p Dave
93 * Make beam sound pausing and unpausing much safer.
95 * 181 9/08/99 10:01p Dave
96 * Make sure game won't run in a drive's root directory. Make sure
97 * standalone routes suqad war messages properly to the host.
99 * 180 9/08/99 3:22p Dave
100 * Updated builtin mission list.
102 * 179 9/08/99 12:01p Jefff
103 * fixed Game_builtin_mission_list typo on Training-2.fs2
105 * 178 9/08/99 9:48a Andsager
106 * Add force feedback for engine wash.
108 * 177 9/07/99 4:01p Dave
109 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
110 * does everything properly (setting up address when binding). Remove
111 * black rectangle background from UI_INPUTBOX.
113 * 176 9/13/99 2:40a Dave
114 * Comment in full 80 minute CD check for RELEASE_REAL builds.
116 * 175 9/06/99 6:38p Dave
117 * Improved CD detection code.
119 * 174 9/06/99 1:30a Dave
120 * Intermediate checkin. Started on enforcing CD-in-drive to play the
123 * 173 9/06/99 1:16a Dave
124 * Make sure the user sees the intro movie.
126 * 172 9/04/99 8:00p Dave
127 * Fixed up 1024 and 32 bit movie support.
129 * 171 9/03/99 1:32a Dave
130 * CD checking by act. Added support to play 2 cutscenes in a row
131 * seamlessly. Fixed super low level cfile bug related to files in the
132 * root directory of a CD. Added cheat code to set campaign mission # in
135 * 170 9/01/99 10:49p Dave
136 * Added nice SquadWar checkbox to the client join wait screen.
138 * 169 9/01/99 10:14a Dave
141 * 168 8/29/99 4:51p Dave
142 * Fixed damaged checkin.
144 * 167 8/29/99 4:18p Andsager
145 * New "burst" limit for friendly damage. Also credit more damage done
146 * against large friendly ships.
148 * 166 8/27/99 6:38p Alanl
149 * crush the blasted repeating messages bug
151 * 164 8/26/99 9:09p Dave
152 * Force framerate check in everything but a RELEASE_REAL build.
154 * 163 8/26/99 9:45a Dave
155 * First pass at easter eggs and cheats.
157 * 162 8/24/99 8:55p Dave
158 * Make sure nondimming pixels work properly in tech menu.
160 * 161 8/24/99 1:49a Dave
161 * Fixed client-side afterburner stuttering. Added checkbox for no version
162 * checking on PXO join. Made button info passing more friendly between
165 * 160 8/22/99 5:53p Dave
166 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
167 * instead of ship designations for multiplayer players.
169 * 159 8/22/99 1:19p Dave
170 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
171 * which d3d cards are detected.
173 * 158 8/20/99 2:09p Dave
174 * PXO banner cycling.
176 * 157 8/19/99 10:59a Dave
177 * Packet loss detection.
179 * 156 8/19/99 10:12a Alanl
180 * preload mission-specific messages on machines greater than 48MB
182 * 155 8/16/99 4:04p Dave
183 * Big honking checkin.
185 * 154 8/11/99 5:54p Dave
186 * Fixed collision problem. Fixed standalone ghost problem.
188 * 153 8/10/99 7:59p Jefff
191 * 152 8/10/99 6:54p Dave
192 * Mad optimizations. Added paging to the nebula effect.
194 * 151 8/10/99 3:44p Jefff
195 * loads Intelligence information on startup
197 * 150 8/09/99 3:47p Dave
198 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
199 * non-nebula missions.
201 * 149 8/09/99 2:21p Andsager
202 * Fix patching from multiplayer direct to launcher update tab.
204 * 148 8/09/99 10:36a Dave
205 * Version info for game.
207 * 147 8/06/99 9:46p Dave
208 * Hopefully final changes for the demo.
210 * 146 8/06/99 3:34p Andsager
211 * Make title version info "(D)" -> "D" show up nicely
213 * 145 8/06/99 2:59p Adamp
214 * Fixed NT launcher/update problem.
216 * 144 8/06/99 1:52p Dave
217 * Bumped up MAX_BITMAPS for the demo.
219 * 143 8/06/99 12:17p Andsager
220 * Demo: down to just 1 demo dog
222 * 142 8/05/99 9:39p Dave
223 * Yet another new checksum.
225 * 141 8/05/99 6:19p Dave
226 * New demo checksums.
228 * 140 8/05/99 5:31p Andsager
229 * Up demo version 1.01
231 * 139 8/05/99 4:22p Andsager
232 * No time limit on upsell screens. Reverse order of display of upsell
235 * 138 8/05/99 4:17p Dave
236 * Tweaks to client interpolation.
238 * 137 8/05/99 3:52p Danw
240 * 136 8/05/99 3:01p Danw
242 * 135 8/05/99 2:43a Anoop
243 * removed duplicate definition.
245 * 134 8/05/99 2:13a Dave
248 * 133 8/05/99 2:05a Dave
251 * 132 8/05/99 1:22a Andsager
254 * 131 8/04/99 9:51p Andsager
255 * Add title screen to demo
257 * 130 8/04/99 6:47p Jefff
258 * fixed link error resulting from #ifdefs
260 * 129 8/04/99 6:26p Dave
261 * Updated ship tbl checksum.
263 * 128 8/04/99 5:40p Andsager
264 * Add multiple demo dogs
266 * 127 8/04/99 5:36p Andsager
267 * Show upsell screens at end of demo campaign before returning to main
270 * 126 8/04/99 11:42a Danw
271 * tone down EAX reverb
273 * 125 8/04/99 11:23a Dave
274 * Updated demo checksums.
276 * 124 8/03/99 11:02p Dave
277 * Maybe fixed sync problems in multiplayer.
279 * 123 8/03/99 6:21p Jefff
282 * 122 8/03/99 3:44p Andsager
283 * Launch laucher if trying to run FS without first having configured
286 * 121 8/03/99 12:45p Dave
289 * 120 8/02/99 9:13p Dave
292 * 119 7/30/99 10:31p Dave
293 * Added comm menu to the configurable hud files.
295 * 118 7/30/99 5:17p Andsager
296 * first fs2demo checksums
298 * 117 7/29/99 3:09p Anoop
300 * 116 7/29/99 12:05a Dave
301 * Nebula speed optimizations.
303 * 115 7/27/99 8:59a Andsager
304 * Make major, minor version consistent for all builds. Only show major
305 * and minor for launcher update window.
307 * 114 7/26/99 5:50p Dave
308 * Revised ingame join. Better? We'll see....
310 * 113 7/26/99 5:27p Andsager
311 * Add training mission as builtin to demo build
313 * 112 7/24/99 1:54p Dave
314 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
317 * 111 7/22/99 4:00p Dave
318 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
320 * 110 7/21/99 8:10p Dave
321 * First run of supernova effect.
323 * 109 7/20/99 1:49p Dave
324 * Peter Drake build. Fixed some release build warnings.
326 * 108 7/19/99 2:26p Andsager
327 * set demo multiplayer missions
329 * 107 7/18/99 5:19p Dave
330 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
332 * 106 7/16/99 1:50p Dave
333 * 8 bit aabitmaps. yay.
335 * 105 7/15/99 3:07p Dave
336 * 32 bit detection support. Mouse coord commandline.
338 * 104 7/15/99 2:13p Dave
339 * Added 32 bit detection.
341 * 103 7/15/99 9:20a Andsager
342 * FS2_DEMO initial checkin
344 * 102 7/14/99 11:02a Dave
345 * Skill level default back to easy. Blech.
347 * 101 7/09/99 5:54p Dave
348 * Seperated cruiser types into individual types. Added tons of new
349 * briefing icons. Campaign screen.
351 * 100 7/08/99 4:43p Andsager
352 * New check for sparky_hi and print if not found.
354 * 99 7/08/99 10:53a Dave
355 * New multiplayer interpolation scheme. Not 100% done yet, but still
356 * better than the old way.
358 * 98 7/06/99 4:24p Dave
359 * Mid-level checkin. Starting on some potentially cool multiplayer
362 * 97 7/06/99 3:35p Andsager
363 * Allow movie to play before red alert mission.
365 * 96 7/03/99 5:50p Dave
366 * Make rotated bitmaps draw properly in padlock views.
368 * 95 7/02/99 9:55p Dave
369 * Player engine wash sound.
371 * 94 7/02/99 4:30p Dave
372 * Much more sophisticated lightning support.
374 * 93 6/29/99 7:52p Dave
375 * Put in exception handling in FS2.
377 * 92 6/22/99 9:37p Dave
378 * Put in pof spewing.
380 * 91 6/16/99 4:06p Dave
381 * New pilot info popup. Added new draw-bitmap-as-poly function.
383 * 90 6/15/99 1:56p Andsager
384 * For release builds, allow start up in high res only with
387 * 89 6/15/99 9:34a Dave
388 * Fixed key checking in single threaded version of the stamp notification
391 * 88 6/09/99 2:55p Andsager
392 * Allow multiple asteroid subtypes (of large, medium, small) and follow
395 * 87 6/08/99 1:14a Dave
396 * Multi colored hud test.
398 * 86 6/04/99 9:52a Dave
399 * Fixed some rendering problems.
401 * 85 6/03/99 10:15p Dave
402 * Put in temporary main hall screen.
404 * 84 6/02/99 6:18p Dave
405 * Fixed TNT lockup problems! Wheeeee!
407 * 83 6/01/99 3:52p Dave
408 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
409 * dead popup, pxo find player popup, pxo private room popup.
411 * 82 5/26/99 1:28p Jasenw
412 * changed coords for loading ani
414 * 81 5/26/99 11:46a Dave
415 * Added ship-blasting lighting and made the randomization of lighting
416 * much more customizable.
418 * 80 5/24/99 5:45p Dave
419 * Added detail levels to the nebula, with a decent speedup. Split nebula
420 * lightning into its own section.
438 #include "systemvars.h"
443 #include "starfield.h"
444 #include "lighting.h"
449 #include "fireballs.h"
453 #include "floating.h"
454 #include "gamesequence.h"
456 #include "optionsmenu.h"
457 #include "playermenu.h"
458 #include "trainingmenu.h"
459 #include "techmenu.h"
462 #include "hudmessage.h"
464 #include "missiongoals.h"
465 #include "missionparse.h"
470 #include "multiutil.h"
471 #include "multimsgs.h"
475 #include "freespace.h"
476 #include "managepilot.h"
478 #include "contexthelp.h"
481 #include "missionbrief.h"
482 #include "missiondebrief.h"
484 #include "missionshipchoice.h"
486 #include "hudconfig.h"
487 #include "controlsconfig.h"
488 #include "missionmessage.h"
489 #include "missiontraining.h"
491 #include "hudtarget.h"
495 #include "eventmusic.h"
496 #include "animplay.h"
497 #include "missionweaponchoice.h"
498 #include "missionlog.h"
499 #include "audiostr.h"
501 #include "missioncampaign.h"
503 #include "missionhotkey.h"
504 #include "objectsnd.h"
505 #include "cmeasure.h"
507 #include "linklist.h"
508 #include "shockwave.h"
509 #include "afterburner.h"
514 #include "stand_gui.h"
515 #include "pcxutils.h"
516 #include "hudtargetbox.h"
517 #include "multi_xfer.h"
518 #include "hudescort.h"
519 #include "multiutil.h"
522 #include "multiteamselect.h"
525 #include "readyroom.h"
526 #include "mainhallmenu.h"
527 #include "multilag.h"
529 #include "particle.h"
531 #include "multi_ingame.h"
532 #include "snazzyui.h"
533 #include "asteroid.h"
534 #include "popupdead.h"
535 #include "multi_voice.h"
536 #include "missioncmdbrief.h"
537 #include "redalert.h"
538 #include "gameplayhelp.h"
539 #include "multilag.h"
540 #include "staticrand.h"
541 #include "multi_pmsg.h"
542 #include "levelpaging.h"
543 #include "observer.h"
544 #include "multi_pause.h"
545 #include "multi_endgame.h"
546 #include "cutscenes.h"
547 #include "multi_respawn.h"
548 // #include "movie.h"
549 #include "multi_obj.h"
550 #include "multi_log.h"
552 #include "localize.h"
553 #include "osregistry.h"
554 #include "barracks.h"
555 #include "missionpause.h"
557 #include "alphacolors.h"
558 #include "objcollide.h"
561 #include "neblightning.h"
562 #include "shipcontrails.h"
565 #include "multi_dogfight.h"
566 #include "multi_rate.h"
567 #include "muzzleflash.h"
571 #include "mainhalltemp.h"
572 #include "exceptionhandler.h"
576 #include "supernova.h"
577 #include "hudshield.h"
578 // #include "names.h"
580 #include "missionloopbrief.h"
584 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
590 // 1.00.04 5/26/98 MWA -- going final (12 pm)
591 // 1.00.03 5/26/98 MWA -- going final (3 am)
592 // 1.00.02 5/25/98 MWA -- going final
593 // 1.00.01 5/25/98 MWA -- going final
594 // 0.90 5/21/98 MWA -- getting ready for final.
595 // 0.10 4/9/98. Set by MK.
597 // Demo version: (obsolete since DEMO codebase split from tree)
598 // 0.03 4/10/98 AL. Interplay rev
599 // 0.02 4/8/98 MK. Increased when this system was modified.
600 // 0.01 4/7/98? AL. First release to Interplay QA.
603 // 1.00 5/28/98 AL. First release to Interplay QA.
605 void game_level_init(int seed = -1);
606 void game_post_level_init();
607 void game_do_frame();
608 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
609 void game_reset_time();
610 void game_show_framerate(); // draws framerate in lower right corner
612 int Game_no_clear = 0;
614 int Pofview_running = 0;
615 int Nebedit_running = 0;
617 typedef struct big_expl_flash {
618 float max_flash_intensity; // max intensity
619 float cur_flash_intensity; // cur intensity
620 int flash_start; // start time
623 #define FRAME_FILTER 16
625 #define DEFAULT_SKILL_LEVEL 1
626 int Game_skill_level = DEFAULT_SKILL_LEVEL;
628 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
629 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
631 #define EXE_FNAME ("fs2.exe")
632 #define LAUNCHER_FNAME ("freespace2.exe")
634 // JAS: Code for warphole camera.
635 // Needs to be cleaned up.
636 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
637 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
638 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
639 matrix Camera_orient = IDENTITY_MATRIX;
640 float Camera_damping = 1.0f;
641 float Camera_time = 0.0f;
642 float Warpout_time = 0.0f;
643 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
644 int Warpout_sound = -1;
646 int Use_joy_mouse = 0;
647 int Use_palette_flash = 1;
649 int Use_fullscreen_at_startup = 0;
651 int Show_area_effect = 0;
652 object *Last_view_target = NULL;
654 int dogfight_blown = 0;
657 float frametimes[FRAME_FILTER];
658 float frametotal = 0.0f;
662 int Show_framerate = 0;
664 int Show_framerate = 1;
667 int Framerate_cap = 120;
670 int Show_target_debug_info = 0;
671 int Show_target_weapons = 0;
673 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
675 int Debug_octant = -1;
677 fix Game_time_compression = F1_0;
679 // if the ships.tbl the player has is valid
680 int Game_ships_tbl_valid = 0;
682 // if the weapons.tbl the player has is valid
683 int Game_weapons_tbl_valid = 0;
687 extern int Player_attacking_enabled;
691 int Pre_player_entry;
693 int Fred_running = 0;
694 char Game_current_mission_filename[MAX_FILENAME_LEN];
695 int game_single_step = 0;
696 int last_single_step=0;
698 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
699 extern int MSG_WINDOW_Y_START;
700 extern int MSG_WINDOW_HEIGHT;
702 int game_zbuffer = 1;
703 //static int Game_music_paused;
704 static int Game_paused;
708 #define EXPIRE_BAD_CHECKSUM 1
709 #define EXPIRE_BAD_TIME 2
711 extern void ssm_init();
712 extern void ssm_level_init();
713 extern void ssm_process();
715 // static variable to contain the time this version was built
716 // commented out for now until
717 // I figure out how to get the username into the file
718 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
720 // defines and variables used for dumping frame for making trailers.
722 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
723 int Debug_dump_trigger = 0;
724 int Debug_dump_frame_count;
725 int Debug_dump_frame_num = 0;
726 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
729 // amount of time to wait after the player has died before we display the death died popup
730 #define PLAYER_DIED_POPUP_WAIT 2500
731 int Player_died_popup_wait = -1;
732 int Player_multi_died_check = -1;
734 // builtin mission list stuff
736 int Game_builtin_mission_count = 6;
737 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
738 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
739 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
740 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
741 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
742 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
743 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
745 #elif defined(PD_BUILD)
746 int Game_builtin_mission_count = 4;
747 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
748 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
749 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
750 { "sm1-01", (FSB_FROM_VOLITION), "" },
751 { "sm1-05", (FSB_FROM_VOLITION), "" },
753 #elif defined(MULTIPLAYER_BETA)
754 int Game_builtin_mission_count = 17;
755 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
757 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
758 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
759 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
760 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
761 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
762 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
763 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
764 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
765 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
766 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
767 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
768 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
769 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
770 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
771 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
772 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
773 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
775 #elif defined(OEM_BUILD)
776 int Game_builtin_mission_count = 17;
777 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
778 // oem version - act 1 only
779 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
782 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
783 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
784 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
785 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
786 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
787 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
788 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
789 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
790 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
791 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
792 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
793 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
794 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
795 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
796 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
797 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
800 int Game_builtin_mission_count = 92;
801 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
802 // single player campaign
803 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
806 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
807 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
808 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
809 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
810 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
811 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
812 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
813 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
814 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
815 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
816 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
817 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
818 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
819 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
820 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
822 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
823 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
824 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
827 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
828 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
829 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
830 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
831 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
832 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
833 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
834 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
835 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
836 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
839 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
840 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
841 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
845 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
847 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
848 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
849 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
850 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
852 // multiplayer missions
855 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
861 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
862 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
888 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
889 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
900 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
901 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
903 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
904 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
905 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
908 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
909 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
910 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
911 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
912 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
917 // Internal function prototypes
918 void game_maybe_draw_mouse(float frametime);
919 void init_animating_pointer();
920 void load_animating_pointer(char *filename, int dx, int dy);
921 void unload_animating_pointer();
922 void game_do_training_checks();
923 void game_shutdown(void);
924 void game_show_event_debug(float frametime);
925 void game_event_debug_init();
927 void demo_upsell_show_screens();
928 void game_start_subspace_ambient_sound();
929 void game_stop_subspace_ambient_sound();
930 void verify_ships_tbl();
931 void verify_weapons_tbl();
932 void display_title_screen();
934 // loading background filenames
935 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
936 "LoadingBG", // GR_640
937 "2_LoadingBG" // GR_1024
941 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
942 "Loading.ani", // GR_640
943 "2_Loading.ani" // GR_1024
946 #if defined(FS2_DEMO)
947 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
951 #elif defined(OEM_BUILD)
952 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
959 char Game_CDROM_dir[MAX_PATH_LEN];
962 // How much RAM is on this machine. Set in WinMain
963 uint Freespace_total_ram = 0;
966 float Game_flash_red = 0.0f;
967 float Game_flash_green = 0.0f;
968 float Game_flash_blue = 0.0f;
969 float Sun_spot = 0.0f;
970 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
972 // game shudder stuff (in ms)
973 int Game_shudder_time = -1;
974 int Game_shudder_total = 0;
975 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
978 sound_env Game_sound_env;
979 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
980 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
982 int Game_sound_env_update_timestamp;
984 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
987 // WARPIN CRAP END --------------------------------------------------------------------------------------------
989 fs_builtin_mission *game_find_builtin_mission(char *filename)
993 // look through all existing builtin missions
994 for(idx=0; idx<Game_builtin_mission_count; idx++){
995 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
996 return &Game_builtin_mission_list[idx];
1004 int game_get_default_skill_level()
1006 return DEFAULT_SKILL_LEVEL;
1010 void game_flash_reset()
1012 Game_flash_red = 0.0f;
1013 Game_flash_green = 0.0f;
1014 Game_flash_blue = 0.0f;
1016 Big_expl_flash.max_flash_intensity = 0.0f;
1017 Big_expl_flash.cur_flash_intensity = 0.0f;
1018 Big_expl_flash.flash_start = 0;
1021 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1022 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1024 void game_framerate_check_init()
1026 // zero critical time
1027 Gf_critical_time = 0.0f;
1030 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1031 // if this is a glide card
1032 if(gr_screen.mode == GR_GLIDE){
1034 extern GrHwConfiguration hwconfig;
1037 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1038 Gf_critical = 15.0f;
1042 Gf_critical = 10.0f;
1047 Gf_critical = 15.0f;
1050 // d3d. only care about good cards here I guess (TNT)
1052 Gf_critical = 15.0f;
1055 // if this is a glide card
1056 if(gr_screen.mode == GR_GLIDE){
1058 extern GrHwConfiguration hwconfig;
1061 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1062 Gf_critical = 25.0f;
1066 Gf_critical = 20.0f;
1071 Gf_critical = 25.0f;
1074 // d3d. only care about good cards here I guess (TNT)
1076 Gf_critical = 25.0f;
1081 extern float Framerate;
1082 void game_framerate_check()
1086 // if the current framerate is above the critical level, add frametime
1087 if(Framerate >= Gf_critical){
1088 Gf_critical_time += flFrametime;
1091 if(!Show_framerate){
1095 // display if we're above the critical framerate
1096 if(Framerate < Gf_critical){
1097 gr_set_color_fast(&Color_bright_red);
1098 gr_string(200, y_start, "Framerate warning");
1103 // display our current pct of good frametime
1104 if(f2fl(Missiontime) >= 0.0f){
1105 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1108 gr_set_color_fast(&Color_bright_green);
1110 gr_set_color_fast(&Color_bright_red);
1113 gr_printf(200, y_start, "%d%%", (int)pct);
1120 // Adds a flash effect. These can be positive or negative.
1121 // The range will get capped at around -1 to 1, so stick
1122 // with a range like that.
1123 void game_flash( float r, float g, float b )
1125 Game_flash_red += r;
1126 Game_flash_green += g;
1127 Game_flash_blue += b;
1129 if ( Game_flash_red < -1.0f ) {
1130 Game_flash_red = -1.0f;
1131 } else if ( Game_flash_red > 1.0f ) {
1132 Game_flash_red = 1.0f;
1135 if ( Game_flash_green < -1.0f ) {
1136 Game_flash_green = -1.0f;
1137 } else if ( Game_flash_green > 1.0f ) {
1138 Game_flash_green = 1.0f;
1141 if ( Game_flash_blue < -1.0f ) {
1142 Game_flash_blue = -1.0f;
1143 } else if ( Game_flash_blue > 1.0f ) {
1144 Game_flash_blue = 1.0f;
1149 // Adds a flash for Big Ship explosions
1150 // cap range from 0 to 1
1151 void big_explosion_flash(float flash)
1153 Big_expl_flash.flash_start = timestamp(1);
1157 } else if (flash < 0.0f) {
1161 Big_expl_flash.max_flash_intensity = flash;
1162 Big_expl_flash.cur_flash_intensity = 0.0f;
1165 // Amount to diminish palette towards normal, per second.
1166 #define DIMINISH_RATE 0.75f
1167 #define SUN_DIMINISH_RATE 6.00f
1171 float sn_glare_scale = 1.7f;
1174 dc_get_arg(ARG_FLOAT);
1175 sn_glare_scale = Dc_arg_float;
1178 float Supernova_last_glare = 0.0f;
1179 void game_sunspot_process(float frametime)
1183 float Sun_spot_goal = 0.0f;
1186 sn_stage = supernova_active();
1188 // sunspot differently based on supernova stage
1190 // approaching. player still in control
1193 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1196 light_get_global_dir(&light_dir, 0);
1198 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1201 // scale it some more
1202 dot = dot * (0.5f + (pct * 0.5f));
1205 Sun_spot_goal += (dot * sn_glare_scale);
1208 // draw the sun glow
1209 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1210 // draw the glow for this sun
1211 stars_draw_sun_glow(0);
1214 Supernova_last_glare = Sun_spot_goal;
1217 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1220 Sun_spot_goal = 0.9f;
1221 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1223 if(Sun_spot_goal > 1.0f){
1224 Sun_spot_goal = 1.0f;
1227 Sun_spot_goal *= sn_glare_scale;
1228 Supernova_last_glare = Sun_spot_goal;
1231 // fade to white. display dead popup
1234 Supernova_last_glare += (2.0f * flFrametime);
1235 if(Supernova_last_glare > 2.0f){
1236 Supernova_last_glare = 2.0f;
1239 Sun_spot_goal = Supernova_last_glare;
1246 // check sunspots for all suns
1247 n_lights = light_get_global_count();
1250 for(idx=0; idx<n_lights; idx++){
1251 //(vector *eye_pos, matrix *eye_orient)
1252 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1255 light_get_global_dir(&light_dir, idx);
1257 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1259 Sun_spot_goal += (float)pow(dot,85.0f);
1261 // draw the glow for this sun
1262 stars_draw_sun_glow(idx);
1264 Sun_spot_goal = 0.0f;
1270 Sun_spot_goal = 0.0f;
1274 float dec_amount = frametime*SUN_DIMINISH_RATE;
1276 if ( Sun_spot < Sun_spot_goal ) {
1277 Sun_spot += dec_amount;
1278 if ( Sun_spot > Sun_spot_goal ) {
1279 Sun_spot = Sun_spot_goal;
1281 } else if ( Sun_spot > Sun_spot_goal ) {
1282 Sun_spot -= dec_amount;
1283 if ( Sun_spot < Sun_spot_goal ) {
1284 Sun_spot = Sun_spot_goal;
1290 // Call once a frame to diminish the
1291 // flash effect to 0.
1292 void game_flash_diminish(float frametime)
1294 float dec_amount = frametime*DIMINISH_RATE;
1296 if ( Game_flash_red > 0.0f ) {
1297 Game_flash_red -= dec_amount;
1298 if ( Game_flash_red < 0.0f )
1299 Game_flash_red = 0.0f;
1301 Game_flash_red += dec_amount;
1302 if ( Game_flash_red > 0.0f )
1303 Game_flash_red = 0.0f;
1306 if ( Game_flash_green > 0.0f ) {
1307 Game_flash_green -= dec_amount;
1308 if ( Game_flash_green < 0.0f )
1309 Game_flash_green = 0.0f;
1311 Game_flash_green += dec_amount;
1312 if ( Game_flash_green > 0.0f )
1313 Game_flash_green = 0.0f;
1316 if ( Game_flash_blue > 0.0f ) {
1317 Game_flash_blue -= dec_amount;
1318 if ( Game_flash_blue < 0.0f )
1319 Game_flash_blue = 0.0f;
1321 Game_flash_blue += dec_amount;
1322 if ( Game_flash_blue > 0.0f )
1323 Game_flash_blue = 0.0f;
1326 // update big_explosion_cur_flash
1327 #define TIME_UP 1500
1328 #define TIME_DOWN 2500
1329 int duration = TIME_UP + TIME_DOWN;
1330 int time = timestamp_until(Big_expl_flash.flash_start);
1331 if (time > -duration) {
1333 if (time < TIME_UP) {
1334 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1337 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1341 if ( Use_palette_flash ) {
1343 // static int or=0, og=0, ob=0;
1345 // Change the 200 to change the color range of colors.
1346 r = fl2i( Game_flash_red*128.0f );
1347 g = fl2i( Game_flash_green*128.0f );
1348 b = fl2i( Game_flash_blue*128.0f );
1350 if ( Sun_spot > 0.0f ) {
1351 r += fl2i(Sun_spot*128.0f);
1352 g += fl2i(Sun_spot*128.0f);
1353 b += fl2i(Sun_spot*128.0f);
1356 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1357 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1358 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1359 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1362 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1363 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1364 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1366 if ( (r!=0) || (g!=0) || (b!=0) ) {
1367 gr_flash( r, g, b );
1369 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1380 void game_level_close()
1382 // De-Initialize the game subsystems
1383 message_mission_shutdown();
1384 event_music_level_close();
1385 game_stop_looped_sounds();
1387 obj_snd_level_close(); // uninit object-linked persistant sounds
1388 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1389 anim_level_close(); // stop and clean up any anim instances
1390 shockwave_level_close();
1391 fireball_level_close();
1393 mission_event_shutdown();
1394 asteroid_level_close();
1395 model_cache_reset(); // Reset/free all the model caching stuff
1396 flak_level_close(); // unload flak stuff
1397 neb2_level_close(); // shutdown gaseous nebula stuff
1400 mflash_level_close();
1402 audiostream_unpause_all();
1407 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1408 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1409 void game_level_init(int seed)
1411 // seed the random number generator
1413 // if no seed was passed, seed the generator either from the time value, or from the
1414 // netgame security flags -- ensures that all players in multiplayer game will have the
1415 // same randon number sequence (with static rand functions)
1416 if ( Game_mode & GM_NORMAL ) {
1417 Game_level_seed = time(NULL);
1419 Game_level_seed = Netgame.security;
1422 // mwa 9/17/98 -- maybe this assert isn't needed????
1423 Assert( !(Game_mode & GM_MULTIPLAYER) );
1424 Game_level_seed = seed;
1426 srand( Game_level_seed );
1428 // semirand function needs to get re-initted every time in multiplayer
1429 if ( Game_mode & GM_MULTIPLAYER ){
1435 Key_normal_game = (Game_mode & GM_NORMAL);
1438 Game_shudder_time = -1;
1440 // Initialize the game subsystems
1441 // timestamp_reset(); // Must be inited before everything else
1443 game_reset_time(); // resets time, and resets saved time too
1445 obj_init(); // Must be inited before the other systems
1446 model_free_all(); // Free all existing models
1447 mission_brief_common_init(); // Free all existing briefing/debriefing text
1448 weapon_level_init();
1449 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1451 player_level_init();
1452 shipfx_flash_init(); // Init the ship gun flash system.
1453 game_flash_reset(); // Reset the flash effect
1454 particle_init(); // Reset the particle system
1458 shield_hit_init(); // Initialize system for showing shield hits
1459 radar_mission_init();
1460 mission_init_goals();
1463 obj_snd_level_init(); // init object-linked persistant sounds
1465 shockwave_level_init();
1466 afterburner_level_init();
1467 scoring_level_init( &Player->stats );
1469 asteroid_level_init();
1470 control_config_clear_used_status();
1471 collide_ship_ship_sounds_init();
1473 Pre_player_entry = 1; // Means the player has not yet entered.
1474 Entry_delay_time = 0; // Could get overwritten in mission read.
1475 fireball_preload(); // page in warphole bitmaps
1477 flak_level_init(); // initialize flak - bitmaps, etc
1478 ct_level_init(); // initialize ships contrails, etc
1479 awacs_level_init(); // initialize AWACS
1480 beam_level_init(); // initialize beam weapons
1481 mflash_level_init();
1483 supernova_level_init();
1485 // multiplayer dogfight hack
1488 shipfx_engine_wash_level_init();
1492 Last_view_target = NULL;
1497 // campaign wasn't ended
1498 Campaign_ended_in_mission = 0;
1501 // called when a mission is over -- does server specific stuff.
1502 void freespace_stop_mission()
1505 Game_mode &= ~GM_IN_MISSION;
1508 // called at frame interval to process networking stuff
1509 void game_do_networking()
1511 Assert( Net_player != NULL );
1512 if (!(Game_mode & GM_MULTIPLAYER)){
1516 // see if this player should be reading/writing data. Bit is set when at join
1517 // screen onward until quits back to main menu.
1518 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1522 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1525 multi_pause_do_frame();
1530 // Loads the best palette for this level, based
1531 // on nebula color and hud color. You could just call palette_load_table with
1532 // the appropriate filename, but who wants to do that.
1533 void game_load_palette()
1535 char palette_filename[1024];
1537 // We only use 3 hud colors right now
1538 // Assert( HUD_config.color >= 0 );
1539 // Assert( HUD_config.color <= 2 );
1541 Assert( Mission_palette >= 0 );
1542 Assert( Mission_palette <= 98 );
1544 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1545 strcpy( palette_filename, NOX("gamepalette-subspace") );
1547 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1550 mprintf(( "Loading palette %s\n", palette_filename ));
1552 // palette_load_table(palette_filename);
1555 void game_post_level_init()
1557 // Stuff which gets called after mission is loaded. Because player isn't created until
1558 // after mission loads, some things must get initted after the level loads
1560 model_level_post_init();
1563 hud_setup_escort_list();
1564 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1570 game_event_debug_init();
1573 training_mission_init();
1574 asteroid_create_all();
1576 game_framerate_check_init();
1580 // An estimate as to how high the count passed to game_loading_callback will go.
1581 // This is just a guess, it seems to always be about the same. The count is
1582 // proportional to the code being executed, not the time, so this works good
1583 // for a bar, assuming the code does about the same thing each time you
1584 // load a level. You can find this value by looking at the return value
1585 // of game_busy_callback(NULL), which I conveniently print out to the
1586 // debug output window with the '=== ENDING LOAD ==' stuff.
1587 //#define COUNT_ESTIMATE 3706
1588 #define COUNT_ESTIMATE 1111
1590 int Game_loading_callback_inited = 0;
1592 int Game_loading_background = -1;
1593 anim * Game_loading_ani = NULL;
1594 anim_instance *Game_loading_ani_instance;
1595 int Game_loading_frame=-1;
1597 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1606 // This gets called 10x per second and count is the number of times
1607 // game_busy() has been called since the current callback function
1609 void game_loading_callback(int count)
1611 game_do_networking();
1613 Assert( Game_loading_callback_inited==1 );
1614 Assert( Game_loading_ani != NULL );
1616 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1617 if ( framenum > Game_loading_ani->total_frames-1 ) {
1618 framenum = Game_loading_ani->total_frames-1;
1619 } else if ( framenum < 0 ) {
1624 while ( Game_loading_frame < framenum ) {
1625 Game_loading_frame++;
1626 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1630 if ( cbitmap > -1 ) {
1631 if ( Game_loading_background > -1 ) {
1632 gr_set_bitmap( Game_loading_background );
1636 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1637 gr_set_bitmap( cbitmap );
1638 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1640 bm_release(cbitmap);
1646 void game_loading_callback_init()
1648 Assert( Game_loading_callback_inited==0 );
1650 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1651 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1654 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1655 Assert( Game_loading_ani != NULL );
1656 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1657 Assert( Game_loading_ani_instance != NULL );
1658 Game_loading_frame = -1;
1660 Game_loading_callback_inited = 1;
1662 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1667 void game_loading_callback_close()
1669 Assert( Game_loading_callback_inited==1 );
1671 // Make sure bar shows all the way over.
1672 game_loading_callback(COUNT_ESTIMATE);
1674 int real_count = game_busy_callback( NULL );
1677 Game_loading_callback_inited = 0;
1680 mprintf(( "=================== ENDING LOAD ================\n" ));
1681 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1682 mprintf(( "================================================\n" ));
1684 // to remove warnings in release build
1688 free_anim_instance(Game_loading_ani_instance);
1689 Game_loading_ani_instance = NULL;
1690 anim_free(Game_loading_ani);
1691 Game_loading_ani = NULL;
1693 bm_release( Game_loading_background );
1694 common_free_interface_palette(); // restore game palette
1695 Game_loading_background = -1;
1697 gr_set_font( FONT1 );
1700 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1702 void game_maybe_update_sound_environment()
1704 // do nothing for now
1707 // Assign the sound environment for the game, based on the current mission
1709 void game_assign_sound_environment()
1712 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1713 Game_sound_env.id = SND_ENV_DRUGGED;
1714 Game_sound_env.volume = 0.800f;
1715 Game_sound_env.damping = 1.188f;
1716 Game_sound_env.decay = 6.392f;
1718 } else if (Num_asteroids > 30) {
1719 Game_sound_env.id = SND_ENV_AUDITORIUM;
1720 Game_sound_env.volume = 0.603f;
1721 Game_sound_env.damping = 0.5f;
1722 Game_sound_env.decay = 4.279f;
1725 Game_sound_env = Game_default_sound_env;
1729 Game_sound_env = Game_default_sound_env;
1730 Game_sound_env_update_timestamp = timestamp(1);
1733 // function which gets called before actually entering the mission. It is broken down into a funciton
1734 // since it will get called in one place from a single player game and from another place for
1735 // a multiplayer game
1736 void freespace_mission_load_stuff()
1738 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1739 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1740 if(!(Game_mode & GM_STANDALONE_SERVER)){
1742 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1744 game_loading_callback_init();
1746 event_music_level_init(); // preloads the first 2 seconds for each event music track
1749 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1752 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1755 ship_assign_sound_all(); // assign engine sounds to ships
1756 game_assign_sound_environment(); // assign the sound environment for this mission
1759 // call function in missionparse.cpp to fixup player/ai stuff.
1760 mission_parse_fixup_players();
1763 // Load in all the bitmaps for this level
1768 game_loading_callback_close();
1770 // the only thing we need to call on the standalone for now.
1772 // call function in missionparse.cpp to fixup player/ai stuff.
1773 mission_parse_fixup_players();
1775 // Load in all the bitmaps for this level
1781 uint load_mission_load;
1782 uint load_post_level_init;
1783 uint load_mission_stuff;
1785 // tells the server to load the mission and initialize structures
1786 int game_start_mission()
1788 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1790 load_gl_init = time(NULL);
1792 load_gl_init = time(NULL) - load_gl_init;
1794 if (Game_mode & GM_MULTIPLAYER) {
1795 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1797 // clear multiplayer stats
1798 init_multiplayer_stats();
1801 load_mission_load = time(NULL);
1802 if (mission_load()) {
1803 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1804 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1805 gameseq_post_event(GS_EVENT_MAIN_MENU);
1807 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1812 load_mission_load = time(NULL) - load_mission_load;
1814 // If this is a red alert mission in campaign mode, bash wingman status
1815 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1816 red_alert_bash_wingman_status();
1819 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1820 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1821 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1822 // game_load_palette();
1825 load_post_level_init = time(NULL);
1826 game_post_level_init();
1827 load_post_level_init = time(NULL) - load_post_level_init;
1831 void Do_model_timings_test();
1832 Do_model_timings_test();
1836 load_mission_stuff = time(NULL);
1837 freespace_mission_load_stuff();
1838 load_mission_stuff = time(NULL) - load_mission_stuff;
1843 int Interface_framerate = 0;
1846 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1847 DCF_BOOL( show_framerate, Show_framerate )
1848 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1849 DCF_BOOL( show_target_weapons, Show_target_weapons )
1850 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1851 DCF_BOOL( sound, Sound_enabled )
1852 DCF_BOOL( zbuffer, game_zbuffer )
1853 DCF_BOOL( shield_system, New_shield_system )
1854 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1855 DCF_BOOL( player_attacking, Player_attacking_enabled )
1856 DCF_BOOL( show_waypoints, Show_waypoints )
1857 DCF_BOOL( show_area_effect, Show_area_effect )
1858 DCF_BOOL( show_net_stats, Show_net_stats )
1859 DCF_BOOL( log, Log_debug_output_to_file )
1860 DCF_BOOL( training_msg_method, Training_msg_method )
1861 DCF_BOOL( show_player_pos, Show_player_pos )
1862 DCF_BOOL(i_framerate, Interface_framerate )
1864 DCF(show_mem,"Toggles showing mem usage")
1867 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1868 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1869 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1870 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1876 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1878 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1879 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1883 DCF(show_cpu,"Toggles showing cpu usage")
1886 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1887 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1888 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1889 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1895 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1897 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1898 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1905 // AL 4-8-98: always allow players to display their framerate
1908 DCF_BOOL( show_framerate, Show_framerate )
1915 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1918 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1919 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1920 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1921 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1923 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" );
1924 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1926 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1929 DCF(palette_flash,"Toggles palette flash effect on/off")
1932 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1933 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1934 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1935 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1937 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1938 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1941 int Use_low_mem = 0;
1943 DCF(low_mem,"Uses low memory settings regardless of RAM")
1946 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1947 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1948 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1949 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1951 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1952 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1954 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1960 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1963 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1964 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1965 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1966 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1968 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1969 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1970 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1974 int Framerate_delay = 0;
1976 float Freespace_gamma = 1.0f;
1978 DCF(gamma,"Sets Gamma factor")
1981 dc_get_arg(ARG_FLOAT|ARG_NONE);
1982 if ( Dc_arg_type & ARG_FLOAT ) {
1983 Freespace_gamma = Dc_arg_float;
1985 dc_printf( "Gamma reset to 1.0f\n" );
1986 Freespace_gamma = 1.0f;
1988 if ( Freespace_gamma < 0.1f ) {
1989 Freespace_gamma = 0.1f;
1990 } else if ( Freespace_gamma > 5.0f ) {
1991 Freespace_gamma = 5.0f;
1993 gr_set_gamma(Freespace_gamma);
1995 char tmp_gamma_string[32];
1996 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1997 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2001 dc_printf( "Usage: gamma <float>\n" );
2002 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2003 Dc_status = 0; // don't print status if help is printed. Too messy.
2007 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2016 Game_current_mission_filename[0] = 0;
2018 // seed the random number generator
2019 Game_init_seed = time(NULL);
2020 srand( Game_init_seed );
2022 Framerate_delay = 0;
2028 extern void bm_init();
2034 // Initialize the timer before the os
2042 GetCurrentDirectory(1024, whee);
2045 strcpy(whee,".\\.");
2049 strcat(whee, EXE_FNAME);
2051 //Initialize the libraries
2052 s1 = timer_get_milliseconds();
2053 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2056 e1 = timer_get_milliseconds();
2058 // time a bunch of cfopens
2060 s2 = timer_get_milliseconds();
2062 for(int idx=0; idx<10000; idx++){
2063 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2068 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2070 e2 = timer_get_milliseconds();
2073 if (Is_standalone) {
2074 std_init_standalone();
2076 os_init( Osreg_class_name, Osreg_app_name );
2077 os_set_title(Osreg_title);
2080 // initialize localization module. Make sure this is down AFTER initialzing OS.
2081 // int t1 = timer_get_milliseconds();
2084 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2086 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2089 // verify that he has a valid weapons.tbl
2090 verify_weapons_tbl();
2092 // Output version numbers to registry for auto patching purposes
2093 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2094 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2095 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2097 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2098 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2099 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2102 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2106 Asteroids_enabled = 1;
2109 /////////////////////////////
2111 /////////////////////////////
2116 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2117 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2119 if (!stricmp(ptr, NOX("no sound"))) {
2120 Cmdline_freespace_no_sound = 1;
2122 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2124 } else if (!stricmp(ptr, NOX("EAX"))) {
2129 if (!Is_standalone) {
2130 snd_init(use_a3d, use_eax);
2132 /////////////////////////////
2134 /////////////////////////////
2136 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2139 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);
2141 // fire up the UpdateLauncher executable
2143 PROCESS_INFORMATION pi;
2145 memset( &si, 0, sizeof(STARTUPINFO) );
2148 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2149 NULL, // pointer to command line string
2150 NULL, // pointer to process security attributes
2151 NULL, // pointer to thread security attributes
2152 FALSE, // handle inheritance flag
2153 CREATE_DEFAULT_ERROR_MODE, // creation flags
2154 NULL, // pointer to new environment block
2155 NULL, // pointer to current directory name
2156 &si, // pointer to STARTUPINFO
2157 &pi // pointer to PROCESS_INFORMATION
2160 // If the Launcher could not be started up, let the user know
2162 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2171 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2173 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);
2181 // check for hi res pack file
2182 int has_sparky_hi = 0;
2184 // check if sparky_hi exists -- access mode 0 means does file exist
2187 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2190 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2193 // see if we've got 32 bit in the string
2194 if(strstr(ptr, "32 bit")){
2200 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2202 // always 640 for E3
2203 gr_init(GR_640, GR_GLIDE);
2205 // regular or hi-res ?
2207 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2209 if(strstr(ptr, NOX("(1024x768)"))){
2211 gr_init(GR_1024, GR_GLIDE);
2213 gr_init(GR_640, GR_GLIDE);
2216 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2218 // always 640 for E3
2220 gr_init(GR_640, GR_DIRECT3D, depth);
2222 // regular or hi-res ?
2224 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2226 if(strstr(ptr, NOX("(1024x768)"))){
2230 gr_init(GR_1024, GR_DIRECT3D, depth);
2234 gr_init(GR_640, GR_DIRECT3D, depth);
2240 if ( Use_fullscreen_at_startup && !Is_standalone) {
2241 gr_init(GR_640, GR_DIRECTDRAW);
2243 gr_init(GR_640, GR_SOFTWARE);
2246 if ( !Is_standalone ) {
2247 gr_init(GR_640, GR_DIRECTDRAW);
2249 gr_init(GR_640, GR_SOFTWARE);
2255 extern int Gr_inited;
2256 if(trying_d3d && !Gr_inited){
2257 extern char Device_init_error[512];
2259 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2268 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2269 Freespace_gamma = (float)atof(ptr);
2270 if ( Freespace_gamma < 0.1f ) {
2271 Freespace_gamma = 0.1f;
2272 } else if ( Freespace_gamma > 5.0f ) {
2273 Freespace_gamma = 5.0f;
2275 char tmp_gamma_string[32];
2276 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2277 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2279 gr_set_gamma(Freespace_gamma);
2281 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2284 display_title_screen();
2288 // attempt to load up master tracker registry info (login and password)
2289 Multi_tracker_id = -1;
2291 // pxo login and password
2292 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2294 nprintf(("Network","Error reading in PXO login data\n"));
2295 strcpy(Multi_tracker_login,"");
2297 strcpy(Multi_tracker_login,ptr);
2299 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2301 nprintf(("Network","Error reading PXO password\n"));
2302 strcpy(Multi_tracker_passwd,"");
2304 strcpy(Multi_tracker_passwd,ptr);
2307 // pxo squad name and password
2308 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2310 nprintf(("Network","Error reading in PXO squad name\n"));
2311 strcpy(Multi_tracker_squad_name, "");
2313 strcpy(Multi_tracker_squad_name, ptr);
2316 // If less than 48MB of RAM, use low memory model.
2317 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2318 mprintf(( "Using normal memory settings...\n" ));
2319 bm_set_low_mem(1); // Use every other frame of bitmaps
2321 mprintf(( "Using high memory settings...\n" ));
2322 bm_set_low_mem(0); // Use all frames of bitmaps
2325 // load non-darkening pixel defs
2326 palman_load_pixels();
2328 // hud shield icon stuff
2329 hud_shield_game_init();
2331 control_config_common_init(); // sets up localization stuff in the control config
2337 gamesnd_parse_soundstbl();
2342 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2347 player_controls_init();
2350 //if(!Is_standalone){
2358 ship_init(); // read in ships.tbl
2360 mission_campaign_init(); // load in the default campaign
2362 // navmap_init(); // init the navigation map system
2363 context_help_init();
2364 techroom_intel_init(); // parse species.tbl, load intel info
2366 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2367 init_animating_pointer();
2369 mission_brief_common_init(); // Mark all the briefing structures as empty.
2370 gr_font_init(); // loads up all fonts
2372 neb2_init(); // fullneb stuff
2376 player_tips_init(); // helpful tips
2379 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2380 pilot_load_pic_list();
2381 pilot_load_squad_pic_list();
2383 load_animating_pointer(NOX("cursor"), 0, 0);
2385 // initialize alpha colors
2386 alpha_colors_init();
2389 // Game_music_paused = 0;
2396 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2397 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2399 mprintf(("cfile_init() took %d\n", e1 - s1));
2400 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2403 char transfer_text[128];
2405 float Start_time = 0.0f;
2407 float Framerate = 0.0f;
2409 float Timing_total = 0.0f;
2410 float Timing_render2 = 0.0f;
2411 float Timing_render3 = 0.0f;
2412 float Timing_flip = 0.0f;
2413 float Timing_clear = 0.0f;
2415 MONITOR(NumPolysDrawn);
2421 void game_get_framerate()
2423 char text[128] = "";
2425 if ( frame_int == -1 ) {
2427 for (i=0; i<FRAME_FILTER; i++ ) {
2428 frametimes[i] = 0.0f;
2433 frametotal -= frametimes[frame_int];
2434 frametotal += flFrametime;
2435 frametimes[frame_int] = flFrametime;
2436 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2438 if ( frametotal != 0.0 ) {
2439 if ( Framecount >= FRAME_FILTER )
2440 Framerate = FRAME_FILTER / frametotal;
2442 Framerate = Framecount / frametotal;
2443 sprintf( text, NOX("FPS: %.1f"), Framerate );
2445 sprintf( text, NOX("FPS: ?") );
2449 if (Show_framerate) {
2450 gr_set_color_fast(&HUD_color_debug);
2451 gr_string( 570, 2, text );
2455 void game_show_framerate()
2459 cur_time = f2fl(timer_get_approx_seconds());
2460 if (cur_time - Start_time > 30.0f) {
2461 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2462 Start_time += 1000.0f;
2465 //mprintf(( "%s\n", text ));
2468 if ( Debug_dump_frames )
2472 // possibly show control checking info
2473 control_check_indicate();
2475 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2476 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2477 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2478 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2481 if ( Show_cpu == 1 ) {
2486 dy = gr_get_font_height() + 1;
2488 gr_set_color_fast(&HUD_color_debug);
2492 extern int D3D_textures_in;
2493 extern int D3D_textures_in_frame;
2494 extern int Glide_textures_in;
2495 extern int Glide_textures_in_frame;
2496 extern int Glide_explosion_vram;
2497 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2499 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2501 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2507 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2509 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2511 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2513 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2515 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2520 extern int Num_pairs; // Number of object pairs that were checked.
2521 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2524 extern int Num_pairs_checked; // What percent of object pairs were checked.
2525 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2527 Num_pairs_checked = 0;
2531 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2534 if ( Timing_total > 0.01f ) {
2535 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2537 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2539 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2541 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2543 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2553 dy = gr_get_font_height() + 1;
2555 gr_set_color_fast(&HUD_color_debug);
2558 extern int TotalRam;
2559 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2564 extern int Model_ram;
2565 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2569 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2571 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2573 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2577 extern int D3D_textures_in;
2578 extern int Glide_textures_in;
2579 extern int Glide_textures_in_frame;
2580 extern int Glide_explosion_vram;
2581 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2583 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2585 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2594 if ( Show_player_pos ) {
2598 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));
2601 MONITOR_INC(NumPolys, modelstats_num_polys);
2602 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2603 MONITOR_INC(NumVerts, modelstats_num_verts );
2605 modelstats_num_polys = 0;
2606 modelstats_num_polys_drawn = 0;
2607 modelstats_num_verts = 0;
2608 modelstats_num_sortnorms = 0;
2612 void game_show_standalone_framerate()
2614 float frame_rate=30.0f;
2615 if ( frame_int == -1 ) {
2617 for (i=0; i<FRAME_FILTER; i++ ) {
2618 frametimes[i] = 0.0f;
2623 frametotal -= frametimes[frame_int];
2624 frametotal += flFrametime;
2625 frametimes[frame_int] = flFrametime;
2626 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2628 if ( frametotal != 0.0 ) {
2629 if ( Framecount >= FRAME_FILTER ){
2630 frame_rate = FRAME_FILTER / frametotal;
2632 frame_rate = Framecount / frametotal;
2635 std_set_standalone_fps(frame_rate);
2639 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2640 void game_show_time_left()
2644 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2645 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2646 // checking how much time is left
2648 if ( Mission_end_time == -1 ){
2652 diff = f2i(Mission_end_time - Missiontime);
2653 // be sure to bash to 0. diff could be negative on frame that we quit mission
2658 hud_set_default_color();
2659 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2662 //========================================================================================
2663 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2664 //========================================================================================
2668 DCF(ai_pause,"Pauses ai")
2671 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2672 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2673 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2674 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2677 obj_init_all_ships_physics();
2680 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2681 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2684 DCF(single_step,"Single steps the game")
2687 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2688 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2689 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2690 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2692 last_single_step = 0; // Make so single step waits a frame before stepping
2695 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2696 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2699 DCF_BOOL(physics_pause, physics_paused)
2700 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2701 DCF_BOOL(ai_firing, Ai_firing_enabled )
2703 // Create some simple aliases to these commands...
2704 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2705 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2706 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2707 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2708 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2711 //========================================================================================
2712 //========================================================================================
2715 void game_training_pause_do()
2719 key = game_check_key();
2721 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2728 void game_increase_skill_level()
2731 if (Game_skill_level >= NUM_SKILL_LEVELS){
2732 Game_skill_level = 0;
2736 int Player_died_time;
2738 int View_percent = 100;
2741 DCF(view, "Sets the percent of the 3d view to render.")
2744 dc_get_arg(ARG_INT);
2745 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2746 View_percent = Dc_arg_int;
2748 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2754 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2758 dc_printf("View is set to %d%%\n", View_percent );
2763 // Set the clip region for the 3d rendering window
2764 void game_set_view_clip()
2766 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2767 // Set the clip region for the letterbox "dead view"
2768 int yborder = gr_screen.max_h/4;
2770 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2771 // J.S. I've changed my ways!! See the new "no constants" code!!!
2772 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2774 // Set the clip region for normal view
2775 if ( View_percent >= 100 ) {
2778 int xborder, yborder;
2780 if ( View_percent < 5 ) {
2784 float fp = i2fl(View_percent)/100.0f;
2785 int fi = fl2i(fl_sqrt(fp)*100.0f);
2786 if ( fi > 100 ) fi=100;
2788 xborder = ( gr_screen.max_w*(100-fi) )/200;
2789 yborder = ( gr_screen.max_h*(100-fi) )/200;
2791 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2797 void show_debug_stuff()
2800 int laser_count = 0, missile_count = 0;
2802 for (i=0; i<MAX_OBJECTS; i++) {
2803 if (Objects[i].type == OBJ_WEAPON){
2804 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2806 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2812 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2815 extern int Tool_enabled;
2820 int tst_bitmap = -1;
2822 float tst_offset, tst_offset_total;
2825 void game_tst_frame_pre()
2833 g3_rotate_vertex(&v, &tst_pos);
2834 g3_project_vertex(&v);
2837 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2841 // big ship? always tst
2843 // within 3000 meters
2844 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2848 // within 300 meters
2849 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2856 void game_tst_frame()
2866 tst_time = time(NULL);
2868 // load the tst bitmap
2869 switch((int)frand_range(0.0f, 3.0)){
2871 tst_bitmap = bm_load("ig_jim");
2873 mprintf(("TST 0\n"));
2877 tst_bitmap = bm_load("ig_kan");
2879 mprintf(("TST 1\n"));
2883 tst_bitmap = bm_load("ig_jim");
2885 mprintf(("TST 2\n"));
2889 tst_bitmap = bm_load("ig_kan");
2891 mprintf(("TST 3\n"));
2900 // get the tst bitmap dimensions
2902 bm_get_info(tst_bitmap, &w, &h);
2905 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2907 snd_play(&Snds[SND_VASUDAN_BUP]);
2909 // tst x and direction
2913 tst_offset_total = (float)w;
2914 tst_offset = (float)w;
2916 tst_x = (float)gr_screen.max_w;
2917 tst_offset_total = (float)-w;
2918 tst_offset = (float)w;
2926 float diff = (tst_offset_total / 0.5f) * flFrametime;
2932 tst_offset -= fl_abs(diff);
2933 } else if(tst_mode == 2){
2936 tst_offset -= fl_abs(diff);
2940 gr_set_bitmap(tst_bitmap);
2941 gr_bitmap((int)tst_x, (int)tst_y);
2944 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2948 // if we passed the switch point
2949 if(tst_offset <= 0.0f){
2954 tst_stamp = timestamp(1000);
2955 tst_offset = fl_abs(tst_offset_total);
2966 void game_tst_mark(object *objp, ship *shipp)
2975 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2978 sip = &Ship_info[shipp->ship_info_index];
2985 tst_pos = objp->pos;
2986 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2992 extern void render_shields();
2994 void player_repair_frame(float frametime)
2996 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2998 for(idx=0;idx<MAX_PLAYERS;idx++){
3001 np = &Net_players[idx];
3003 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)){
3005 // don't rearm/repair if the player is dead or dying/departing
3006 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3007 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3012 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3013 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3019 #define NUM_FRAMES_TEST 300
3020 #define NUM_MIXED_SOUNDS 16
3021 void do_timing_test(float flFrametime)
3023 static int framecount = 0;
3024 static int test_running = 0;
3025 static float test_time = 0.0f;
3027 static int snds[NUM_MIXED_SOUNDS];
3030 if ( test_running ) {
3032 test_time += flFrametime;
3033 if ( framecount >= NUM_FRAMES_TEST ) {
3035 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3036 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3041 if ( Test_begin == 1 ) {
3047 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3050 // start looping digital sounds
3051 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3052 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3059 DCF(dcf_fov, "Change the field of view")
3062 dc_get_arg(ARG_FLOAT|ARG_NONE);
3063 if ( Dc_arg_type & ARG_NONE ) {
3064 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3065 dc_printf( "Zoom factor reset\n" );
3067 if ( Dc_arg_type & ARG_FLOAT ) {
3068 if (Dc_arg_float < 0.25f) {
3069 Viewer_zoom = 0.25f;
3070 dc_printf("Zoom factor pinned at 0.25.\n");
3071 } else if (Dc_arg_float > 1.25f) {
3072 Viewer_zoom = 1.25f;
3073 dc_printf("Zoom factor pinned at 1.25.\n");
3075 Viewer_zoom = Dc_arg_float;
3081 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3084 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3088 DCF(framerate_cap, "Sets the framerate cap")
3091 dc_get_arg(ARG_INT);
3092 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3093 Framerate_cap = Dc_arg_int;
3095 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3101 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3102 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3103 dc_printf("[n] must be from 1 to 120.\n");
3107 if ( Framerate_cap )
3108 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3110 dc_printf("There is no framerate cap currently active.\n");
3114 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3115 int Show_viewing_from_self = 0;
3117 void say_view_target()
3119 object *view_target;
3121 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3122 view_target = &Objects[Player_ai->target_objnum];
3124 view_target = Player_obj;
3126 if (Game_mode & GM_DEAD) {
3127 if (Player_ai->target_objnum != -1)
3128 view_target = &Objects[Player_ai->target_objnum];
3131 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3132 if (view_target != Player_obj){
3134 char *view_target_name = NULL;
3135 switch(Objects[Player_ai->target_objnum].type) {
3137 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3140 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3141 Viewer_mode &= ~VM_OTHER_SHIP;
3143 case OBJ_JUMP_NODE: {
3144 char jump_node_name[128];
3145 strcpy(jump_node_name, XSTR( "jump node", 184));
3146 view_target_name = jump_node_name;
3147 Viewer_mode &= ~VM_OTHER_SHIP;
3156 if ( view_target_name ) {
3157 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3158 Show_viewing_from_self = 1;
3161 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3162 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3163 Show_viewing_from_self = 1;
3165 if (Show_viewing_from_self)
3166 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3171 Last_view_target = view_target;
3175 float Game_hit_x = 0.0f;
3176 float Game_hit_y = 0.0f;
3178 // Reset at the beginning of each frame
3179 void game_whack_reset()
3185 // Apply a 2d whack to the player
3186 void game_whack_apply( float x, float y )
3188 // Do some force feedback
3189 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3195 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3198 // call to apply a "shudder"
3199 void game_shudder_apply(int time, float intensity)
3201 Game_shudder_time = timestamp(time);
3202 Game_shudder_total = time;
3203 Game_shudder_intensity = intensity;
3206 #define FF_SCALE 10000
3207 void apply_hud_shake(matrix *eye_orient)
3209 if (Viewer_obj == Player_obj) {
3210 physics_info *pi = &Player_obj->phys_info;
3218 // Make eye shake due to afterburner
3219 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3222 dtime = timestamp_until(pi->afterburner_decay);
3226 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3227 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3230 // Make eye shake due to engine wash
3232 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3235 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3236 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3238 // get the intensity
3239 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3243 vm_vec_rand_vec_quick(&rand_vec);
3246 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3250 // make hud shake due to shuddering
3251 if(Game_shudder_time != -1){
3252 // if the timestamp has elapsed
3253 if(timestamp_elapsed(Game_shudder_time)){
3254 Game_shudder_time = -1;
3256 // otherwise apply some shudder
3260 dtime = timestamp_until(Game_shudder_time);
3264 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));
3265 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));
3270 vm_angles_2_matrix(&tm, &tangles);
3271 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3272 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3273 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3274 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3279 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3281 // Player's velocity just before he blew up. Used to keep camera target moving.
3282 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3284 // Set eye_pos and eye_orient based on view mode.
3285 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3289 static int last_Viewer_mode = 0;
3290 static int last_Game_mode = 0;
3291 static int last_Viewer_objnum = -1;
3293 // This code is supposed to detect camera "cuts"... like going between
3296 // determine if we need to regenerate the nebula
3297 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3298 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3299 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3300 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3301 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3302 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3303 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3304 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3305 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3308 // regenerate the nebula
3312 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3313 //mprintf(( "************** Camera cut! ************\n" ));
3314 last_Viewer_mode = Viewer_mode;
3315 last_Game_mode = Game_mode;
3317 // Camera moved. Tell stars & debris to not do blurring.
3323 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3324 player_display_packlock_view();
3327 game_set_view_clip();
3329 if (Game_mode & GM_DEAD) {
3330 vector vec_to_deader, view_pos;
3333 Viewer_mode |= VM_DEAD_VIEW;
3335 if (Player_ai->target_objnum != -1) {
3336 int view_from_player = 1;
3338 if (Viewer_mode & VM_OTHER_SHIP) {
3339 // View from target.
3340 Viewer_obj = &Objects[Player_ai->target_objnum];
3342 last_Viewer_objnum = Player_ai->target_objnum;
3344 if ( Viewer_obj->type == OBJ_SHIP ) {
3345 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3346 view_from_player = 0;
3349 last_Viewer_objnum = -1;
3352 if ( view_from_player ) {
3353 // View target from player ship.
3355 *eye_pos = Player_obj->pos;
3356 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3357 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3360 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3362 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3363 dist += flFrametime * 16.0f;
3365 vm_vec_scale(&vec_to_deader, -dist);
3366 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3368 view_pos = Player_obj->pos;
3370 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3371 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3372 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3373 Dead_player_last_vel = Player_obj->phys_info.vel;
3374 //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));
3375 } else if (Player_ai->target_objnum != -1) {
3376 view_pos = Objects[Player_ai->target_objnum].pos;
3378 // Make camera follow explosion, but gradually slow down.
3379 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3380 view_pos = Player_obj->pos;
3381 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3382 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3385 *eye_pos = Dead_camera_pos;
3387 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3389 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3394 // if supernova shockwave
3395 if(supernova_camera_cut()){
3399 // call it dead view
3400 Viewer_mode |= VM_DEAD_VIEW;
3402 // set eye pos and orient
3403 supernova_set_view(eye_pos, eye_orient);
3405 // If already blown up, these other modes can override.
3406 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3407 Viewer_mode &= ~VM_DEAD_VIEW;
3409 Viewer_obj = Player_obj;
3411 if (Viewer_mode & VM_OTHER_SHIP) {
3412 if (Player_ai->target_objnum != -1){
3413 Viewer_obj = &Objects[Player_ai->target_objnum];
3414 last_Viewer_objnum = Player_ai->target_objnum;
3416 Viewer_mode &= ~VM_OTHER_SHIP;
3417 last_Viewer_objnum = -1;
3420 last_Viewer_objnum = -1;
3423 if (Viewer_mode & VM_EXTERNAL) {
3426 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3427 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3429 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3431 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3432 vm_vec_normalize(&eye_dir);
3433 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3436 // Modify the orientation based on head orientation.
3437 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3439 } else if ( Viewer_mode & VM_CHASE ) {
3442 if ( Viewer_obj->phys_info.speed < 0.1 )
3443 move_dir = Viewer_obj->orient.fvec;
3445 move_dir = Viewer_obj->phys_info.vel;
3446 vm_vec_normalize(&move_dir);
3449 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3450 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3451 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3452 vm_vec_normalize(&eye_dir);
3454 // JAS: I added the following code because if you slew up using
3455 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3456 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3457 // call because the up and the forward vector are the same. I fixed
3458 // it by adding in a fraction of the right vector all the time to the
3460 vector tmp_up = Viewer_obj->orient.uvec;
3461 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3463 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3466 // Modify the orientation based on head orientation.
3467 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3468 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3469 *eye_pos = Camera_pos;
3471 ship * shipp = &Ships[Player_obj->instance];
3473 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3474 vm_vec_normalize(&eye_dir);
3475 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3478 // get an eye position based upon the correct type of object
3479 switch(Viewer_obj->type){
3481 // make a call to get the eye point for the player object
3482 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3485 // make a call to get the eye point for the player object
3486 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3492 #ifdef JOHNS_DEBUG_CODE
3493 john_debug_stuff(&eye_pos, &eye_orient);
3499 apply_hud_shake(eye_orient);
3501 // setup neb2 rendering
3502 neb2_render_setup(eye_pos, eye_orient);
3506 extern void ai_debug_render_stuff();
3509 int Game_subspace_effect = 0;
3510 DCF_BOOL( subspace, Game_subspace_effect );
3512 // Does everything needed to render a frame
3513 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3517 g3_start_frame(game_zbuffer);
3518 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3520 // maybe offset the HUD (jitter stuff)
3521 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3522 HUD_set_offsets(Viewer_obj, !dont_offset);
3524 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3525 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3526 // must be done before ships are rendered
3527 if ( MULTIPLAYER_CLIENT ) {
3528 shield_point_multi_setup();
3531 if ( Game_subspace_effect ) {
3532 stars_draw(0,0,0,1);
3534 stars_draw(1,1,1,0);
3537 obj_render_all(obj_render);
3538 beam_render_all(); // render all beam weapons
3539 particle_render_all(); // render particles after everything else.
3540 trail_render_all(); // render missilie trails after everything else.
3541 mflash_render_all(); // render all muzzle flashes
3543 // Why do we not show the shield effect in these modes? Seems ok.
3544 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3548 // render nebula lightning
3551 // render local player nebula
3552 neb2_render_player();
3555 ai_debug_render_stuff();
3558 #ifndef RELEASE_REAL
3559 // game_framerate_check();
3563 extern void snd_spew_debug_info();
3564 snd_spew_debug_info();
3567 //================ END OF 3D RENDERING STUFF ====================
3571 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3572 hud_maybe_clear_head_area();
3573 anim_render_all(0, flFrametime);
3576 extern int Multi_display_netinfo;
3577 if(Multi_display_netinfo){
3578 extern void multi_display_netinfo();
3579 multi_display_netinfo();
3582 game_tst_frame_pre();
3585 do_timing_test(flFrametime);
3589 extern int OO_update_index;
3590 multi_rate_display(OO_update_index, 375, 0);
3595 extern void oo_display();
3602 //#define JOHNS_DEBUG_CODE 1
3604 #ifdef JOHNS_DEBUG_CODE
3605 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3607 //if ( keyd_pressed[KEY_LSHIFT] )
3609 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3611 model_subsystem *turret = tsys->system_info;
3613 if (turret->type == SUBSYSTEM_TURRET ) {
3615 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3617 ship_model_start(tobj);
3619 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3620 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3621 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3623 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3625 ship_model_stop(tobj);
3635 // following function for dumping frames for purposes of building trailers.
3638 // function to toggle state of dumping every frame into PCX when playing the game
3639 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3643 if ( Debug_dump_frames == 0 ) {
3645 Debug_dump_frames = 15;
3646 Debug_dump_trigger = 0;
3647 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3648 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3651 Debug_dump_frames = 0;
3652 Debug_dump_trigger = 0;
3653 gr_dump_frame_stop();
3654 dc_printf( "Frame dumping is now OFF\n" );
3660 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3664 if ( Debug_dump_frames == 0 ) {
3666 Debug_dump_frames = 15;
3667 Debug_dump_trigger = 1;
3668 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3669 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3672 Debug_dump_frames = 0;
3673 Debug_dump_trigger = 0;
3674 gr_dump_frame_stop();
3675 dc_printf( "Frame dumping is now OFF\n" );
3681 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3685 if ( Debug_dump_frames == 0 ) {
3687 Debug_dump_frames = 30;
3688 Debug_dump_trigger = 0;
3689 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3690 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3693 Debug_dump_frames = 0;
3694 Debug_dump_trigger = 0;
3695 gr_dump_frame_stop();
3696 dc_printf( "Frame dumping is now OFF\n" );
3702 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3706 if ( Debug_dump_frames == 0 ) {
3708 Debug_dump_frames = 30;
3709 Debug_dump_trigger = 1;
3710 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3711 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3714 Debug_dump_frames = 0;
3715 Debug_dump_trigger = 0;
3716 gr_dump_frame_stop();
3717 dc_printf( "Triggered frame dumping is now OFF\n" );
3723 void game_maybe_dump_frame()
3725 if ( !Debug_dump_frames ){
3729 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3736 Debug_dump_frame_num++;
3742 extern int Player_dead_state;
3744 // Flip the page and time how long it took.
3745 void game_flip_page_and_time_it()
3749 t1 = timer_get_fixed_seconds();
3751 t2 = timer_get_fixed_seconds();
3753 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3754 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3757 void game_simulation_frame()
3759 // blow ships up in multiplayer dogfight
3760 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){
3761 // blow up all non-player ships
3762 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3765 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3767 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)){
3768 moveup = GET_NEXT(moveup);
3771 shipp = &Ships[Objects[moveup->objnum].instance];
3772 sip = &Ship_info[shipp->ship_info_index];
3774 // only blow up small ships
3775 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3776 // function to simply explode a ship where it is currently at
3777 ship_self_destruct( &Objects[moveup->objnum] );
3780 moveup = GET_NEXT(moveup);
3786 // process AWACS stuff - do this first thing
3789 // single player, set Player hits_this_frame to 0
3790 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3791 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3792 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3796 supernova_process();
3797 if(supernova_active() >= 5){
3801 // fire targeting lasers now so that
3802 // 1 - created this frame
3803 // 2 - collide this frame
3804 // 3 - render this frame
3805 // 4 - ignored and deleted next frame
3806 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3808 ship_process_targeting_lasers();
3810 // do this here so that it works for multiplayer
3812 // get viewer direction
3813 int viewer_direction = PHYSICS_VIEWER_REAR;
3815 if(Viewer_mode == 0){
3816 viewer_direction = PHYSICS_VIEWER_FRONT;
3818 if(Viewer_mode & VM_PADLOCK_UP){
3819 viewer_direction = PHYSICS_VIEWER_UP;
3821 else if(Viewer_mode & VM_PADLOCK_REAR){
3822 viewer_direction = PHYSICS_VIEWER_REAR;
3824 else if(Viewer_mode & VM_PADLOCK_LEFT){
3825 viewer_direction = PHYSICS_VIEWER_LEFT;
3827 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3828 viewer_direction = PHYSICS_VIEWER_RIGHT;
3831 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3833 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3836 #define VM_PADLOCK_UP (1 << 7)
3837 #define VM_PADLOCK_REAR (1 << 8)
3838 #define VM_PADLOCK_LEFT (1 << 9)
3839 #define VM_PADLOCK_RIGHT (1 << 10)
3841 // evaluate mission departures and arrivals before we process all objects.
3842 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3844 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3845 // ships/wing packets.
3846 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3847 mission_parse_eval_stuff();
3850 // if we're an observer, move ourselves seperately from the standard physics
3851 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3852 obj_observer_move(flFrametime);
3855 // move all the objects now
3856 obj_move_all(flFrametime);
3858 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3859 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3860 // ship_check_cargo_all();
3861 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3862 mission_eval_goals();
3866 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3867 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3868 training_check_objectives();
3871 // do all interpolation now
3872 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3873 // client side processing of warping in effect stages
3874 multi_do_client_warp(flFrametime);
3876 // client side movement of an observer
3877 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3878 obj_observer_move(flFrametime);
3881 // move all objects - does interpolation now as well
3882 obj_move_all(flFrametime);
3885 // only process the message queue when the player is "in" the game
3886 if ( !Pre_player_entry ){
3887 message_queue_process(); // process any messages send to the player
3890 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3891 message_maybe_distort(); // maybe distort incoming message if comms damaged
3892 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3893 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3894 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3897 if(!(Game_mode & GM_STANDALONE_SERVER)){
3898 // process some stuff every frame (before frame is rendered)
3899 emp_process_local();
3901 hud_update_frame(); // update hud systems
3903 if (!physics_paused) {
3904 // Move particle system
3905 particle_move_all(flFrametime);
3907 // Move missile trails
3908 trail_move_all(flFrametime);
3910 // process muzzle flashes
3911 mflash_process_all();
3913 // Flash the gun flashes
3914 shipfx_flash_do_frame(flFrametime);
3916 shockwave_move_all(flFrametime); // update all the shockwaves
3919 // subspace missile strikes
3922 obj_snd_do_frame(); // update the object-linked persistant sounds
3923 game_maybe_update_sound_environment();
3924 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3926 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3928 if ( Game_subspace_effect ) {
3929 game_start_subspace_ambient_sound();
3935 // Maybe render and process the dead-popup
3936 void game_maybe_do_dead_popup(float frametime)
3938 if ( popupdead_is_active() ) {
3940 int choice = popupdead_do_frame(frametime);
3942 if ( Game_mode & GM_NORMAL ) {
3946 if(game_do_cd_mission_check(Game_current_mission_filename)){
3947 gameseq_post_event(GS_EVENT_ENTER_GAME);
3949 gameseq_post_event(GS_EVENT_MAIN_MENU);
3954 gameseq_post_event(GS_EVENT_END_GAME);
3959 if(game_do_cd_mission_check(Game_current_mission_filename)){
3960 gameseq_post_event(GS_EVENT_START_GAME);
3962 gameseq_post_event(GS_EVENT_MAIN_MENU);
3966 // this should only happen during a red alert mission
3969 Assert(The_mission.red_alert);
3970 if(!The_mission.red_alert){
3972 if(game_do_cd_mission_check(Game_current_mission_filename)){
3973 gameseq_post_event(GS_EVENT_START_GAME);
3975 gameseq_post_event(GS_EVENT_MAIN_MENU);
3980 // choose the previous mission
3981 mission_campaign_previous_mission();
3983 if(game_do_cd_mission_check(Game_current_mission_filename)){
3984 gameseq_post_event(GS_EVENT_START_GAME);
3986 gameseq_post_event(GS_EVENT_MAIN_MENU);
3997 case POPUPDEAD_DO_MAIN_HALL:
3998 multi_quit_game(PROMPT_NONE,-1);
4001 case POPUPDEAD_DO_RESPAWN:
4002 multi_respawn_normal();
4003 event_music_player_respawn();
4006 case POPUPDEAD_DO_OBSERVER:
4007 multi_respawn_observer();
4008 event_music_player_respawn_as_observer();
4017 if ( leave_popup ) {
4023 // returns true if player is actually in a game_play stats
4024 int game_actually_playing()
4028 state = gameseq_get_state();
4029 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4035 // Draw the 2D HUD gauges
4036 void game_render_hud_2d()
4038 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4042 HUD_render_2d(flFrametime);
4046 // Draw the 3D-dependant HUD gauges
4047 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4049 g3_start_frame(0); // 0 = turn zbuffering off
4050 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4052 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4053 HUD_render_3d(flFrametime);
4057 game_sunspot_process(flFrametime);
4059 // Diminish the palette effect
4060 game_flash_diminish(flFrametime);
4068 int actually_playing;
4069 fix total_time1, total_time2;
4070 fix render2_time1=0, render2_time2=0;
4071 fix render3_time1=0, render3_time2=0;
4072 fix flip_time1=0, flip_time2=0;
4073 fix clear_time1=0, clear_time2=0;
4079 if (Framerate_delay) {
4080 int start_time = timer_get_milliseconds();
4081 while (timer_get_milliseconds() < start_time + Framerate_delay)
4087 demo_do_frame_start();
4089 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4094 // start timing frame
4095 timing_frame_start();
4097 total_time1 = timer_get_fixed_seconds();
4099 // var to hold which state we are in
4100 actually_playing = game_actually_playing();
4102 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4103 if (!(Game_mode & GM_STANDALONE_SERVER)){
4104 Assert( OBJ_INDEX(Player_obj) >= 0 );
4108 if (Missiontime > Entry_delay_time){
4109 Pre_player_entry = 0;
4111 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4114 // Note: These are done even before the player enters, else buffers can overflow.
4115 if (! (Game_mode & GM_STANDALONE_SERVER)){
4119 shield_frame_init();
4121 if ( Player->control_mode != PCM_NORMAL )
4124 if ( !Pre_player_entry && actually_playing ) {
4125 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4127 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4128 game_process_keys();
4130 // don't read flying controls if we're playing a demo back
4131 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4132 read_player_controls( Player_obj, flFrametime);
4136 // if we're not the master, we may have to send the server-critical ship status button_info bits
4137 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4138 multi_maybe_send_ship_status();
4143 // Reset the whack stuff
4146 // These two lines must be outside of Pre_player_entry code,
4147 // otherwise too many lights are added.
4150 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4154 game_simulation_frame();
4156 // if not actually in a game play state, then return. This condition could only be true in
4157 // a multiplayer game.
4158 if ( !actually_playing ) {
4159 Assert( Game_mode & GM_MULTIPLAYER );
4163 if (!Pre_player_entry) {
4164 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4165 clear_time1 = timer_get_fixed_seconds();
4166 // clear the screen to black
4168 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4172 clear_time2 = timer_get_fixed_seconds();
4173 render3_time1 = timer_get_fixed_seconds();
4174 game_render_frame_setup(&eye_pos, &eye_orient);
4175 game_render_frame( &eye_pos, &eye_orient );
4177 // save the eye position and orientation
4178 if ( Game_mode & GM_MULTIPLAYER ) {
4179 Net_player->s_info.eye_pos = eye_pos;
4180 Net_player->s_info.eye_orient = eye_orient;
4183 hud_show_target_model();
4185 // check to see if we should display the death died popup
4186 if(Game_mode & GM_DEAD_BLEW_UP){
4187 if(Game_mode & GM_MULTIPLAYER){
4188 // catch the situation where we're supposed to be warping out on this transition
4189 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4190 gameseq_post_event(GS_EVENT_DEBRIEF);
4191 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4192 Player_died_popup_wait = -1;
4196 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4197 Player_died_popup_wait = -1;
4203 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4204 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4205 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4206 if(!popupdead_is_active()){
4210 Player_multi_died_check = -1;
4214 render3_time2 = timer_get_fixed_seconds();
4215 render2_time1 = timer_get_fixed_seconds();
4218 game_get_framerate();
4219 game_show_framerate();
4221 game_show_time_left();
4223 // Draw the 2D HUD gauges
4224 if(supernova_active() < 3){
4225 game_render_hud_2d();
4228 game_set_view_clip();
4230 // Draw 3D HUD gauges
4231 game_render_hud_3d(&eye_pos, &eye_orient);
4235 render2_time2 = timer_get_fixed_seconds();
4237 // maybe render and process the dead popup
4238 game_maybe_do_dead_popup(flFrametime);
4240 // start timing frame
4241 timing_frame_stop();
4242 // timing_display(30, 10);
4244 // If a regular popup is active, don't flip (popup code flips)
4245 if( !popup_running_state() ){
4246 flip_time1 = timer_get_fixed_seconds();
4247 game_flip_page_and_time_it();
4248 flip_time2 = timer_get_fixed_seconds();
4252 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4255 game_show_standalone_framerate();
4259 game_do_training_checks();
4262 // process lightning (nebula only)
4265 total_time2 = timer_get_fixed_seconds();
4267 // Got some timing numbers
4268 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4269 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4270 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4271 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4272 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4275 demo_do_frame_end();
4277 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4283 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4284 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4285 // died. This resulted in screwed up death sequences.
4287 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4288 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4289 static int timer_paused=0;
4290 static int stop_count,start_count;
4291 static int time_stopped,time_started;
4292 int saved_timestamp_ticker = -1;
4294 void game_reset_time()
4296 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4300 // Last_time = timer_get_fixed_seconds();
4306 void game_stop_time()
4308 if (timer_paused==0) {
4310 time = timer_get_fixed_seconds();
4311 // Save how much time progressed so far in the frame so we can
4312 // use it when we unpause.
4313 Last_delta_time = time - Last_time;
4315 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4316 if (Last_delta_time < 0) {
4317 #if defined(TIMER_TEST) && !defined(NDEBUG)
4318 Int3(); //get Matt!!!!
4320 Last_delta_time = 0;
4322 #if defined(TIMER_TEST) && !defined(NDEBUG)
4323 time_stopped = time;
4326 // Stop the timer_tick stuff...
4327 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4328 saved_timestamp_ticker = timestamp_ticker;
4332 #if defined(TIMER_TEST) && !defined(NDEBUG)
4337 void game_start_time()
4340 Assert(timer_paused >= 0);
4341 if (timer_paused==0) {
4343 time = timer_get_fixed_seconds();
4344 #if defined(TIMER_TEST) && !defined(NDEBUG)
4346 Int3(); //get Matt!!!!
4349 // Take current time, and set it backwards to account for time
4350 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4351 // will be correct when it goes to calculate the frametime next
4353 Last_time = time - Last_delta_time;
4354 #if defined(TIMER_TEST) && !defined(NDEBUG)
4355 time_started = time;
4358 // Restore the timer_tick stuff...
4359 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4360 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4361 timestamp_ticker = saved_timestamp_ticker;
4362 saved_timestamp_ticker = -1;
4365 #if defined(TIMER_TEST) && !defined(NDEBUG)
4371 void game_set_frametime(int state)
4374 float frame_cap_diff;
4376 thistime = timer_get_fixed_seconds();
4378 if ( Last_time == 0 )
4379 Frametime = F1_0 / 30;
4381 Frametime = thistime - Last_time;
4383 // Frametime = F1_0 / 30;
4385 fix debug_frametime = Frametime; // Just used to display frametime.
4387 // If player hasn't entered mission yet, make frame take 1/4 second.
4388 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4391 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4393 fix frame_speed = F1_0 / Debug_dump_frames;
4395 if (Frametime > frame_speed ){
4396 nprintf(("warning","slow frame: %x\n",Frametime));
4399 thistime = timer_get_fixed_seconds();
4400 Frametime = thistime - Last_time;
4401 } while (Frametime < frame_speed );
4403 Frametime = frame_speed;
4407 Assert( Framerate_cap > 0 );
4409 // Cap the framerate so it doesn't get too high.
4413 cap = F1_0/Framerate_cap;
4414 if (Frametime < cap) {
4415 thistime = cap - Frametime;
4416 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4417 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4419 thistime = timer_get_fixed_seconds();
4423 if((Game_mode & GM_STANDALONE_SERVER) &&
4424 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4426 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4427 Sleep((DWORD)(frame_cap_diff*1000));
4429 thistime += fl2f((frame_cap_diff));
4431 Frametime = thistime - Last_time;
4434 // If framerate is too low, cap it.
4435 if (Frametime > MAX_FRAMETIME) {
4437 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4439 // to remove warnings in release build
4440 debug_frametime = fl2f(flFrametime);
4442 Frametime = MAX_FRAMETIME;
4445 Frametime = fixmul(Frametime, Game_time_compression);
4447 Last_time = thistime;
4448 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4450 flFrametime = f2fl(Frametime);
4451 //if(!(Game_mode & GM_PLAYING_DEMO)){
4452 timestamp_inc(flFrametime);
4454 /* if ((Framecount > 0) && (Framecount < 10)) {
4455 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4460 // This is called from game_do_frame(), and from navmap_do_frame()
4461 void game_update_missiontime()
4463 // TODO JAS: Put in if and move this into game_set_frametime,
4464 // fix navmap to call game_stop/start_time
4465 //if ( !timer_paused )
4466 Missiontime += Frametime;
4469 void game_do_frame()
4471 game_set_frametime(GS_STATE_GAME_PLAY);
4472 game_update_missiontime();
4474 if (Game_mode & GM_STANDALONE_SERVER) {
4475 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4478 if ( game_single_step && (last_single_step == game_single_step) ) {
4479 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4480 while( key_checkch() == 0 )
4482 os_set_title( XSTR( "FreeSpace", 171) );
4483 Last_time = timer_get_fixed_seconds();
4486 last_single_step = game_single_step;
4488 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4489 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4493 Keep_mouse_centered = 0;
4494 monitor_update(); // Update monitor variables
4497 void multi_maybe_do_frame()
4499 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4504 int Joymouse_button_status = 0;
4506 // Flush all input devices
4514 Joymouse_button_status = 0;
4516 //mprintf(("Game flush!\n" ));
4519 // function for multiplayer only which calls game_do_state_common() when running the
4521 void game_do_dc_networking()
4523 Assert( Game_mode & GM_MULTIPLAYER );
4525 game_do_state_common( gameseq_get_state() );
4528 // Call this whenever in a loop, or when you need to check for a keystroke.
4529 int game_check_key()
4535 // convert keypad enter to normal enter
4536 if ((k & KEY_MASK) == KEY_PADENTER)
4537 k = (k & ~KEY_MASK) | KEY_ENTER;
4544 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4545 static int Demo_show_trailer_timestamp = 0;
4547 void demo_reset_trailer_timer()
4549 Demo_show_trailer_timestamp = timer_get_milliseconds();
4552 void demo_maybe_show_trailer(int k)
4555 // if key pressed, reset demo trailer timer
4557 demo_reset_trailer_timer();
4561 // if mouse moved, reset demo trailer timer
4564 mouse_get_delta(&dx, &dy);
4565 if ( (dx > 0) || (dy > 0) ) {
4566 demo_reset_trailer_timer();
4570 // if joystick has moved, reset demo trailer timer
4573 joy_get_delta(&dx, &dy);
4574 if ( (dx > 0) || (dy > 0) ) {
4575 demo_reset_trailer_timer();
4579 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4580 // the low-level code. Ugly, I know... but was the simplest and most
4583 // if 30 seconds since last demo trailer time reset, launch movie
4584 if ( os_foreground() ) {
4585 int now = timer_get_milliseconds();
4586 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4587 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4589 movie_play( NOX("fstrailer2.mve") );
4590 demo_reset_trailer_timer();
4598 // same as game_check_key(), except this is used while actually in the game. Since there
4599 // generally are differences between game control keys and general UI keys, makes sense to
4600 // have seperate functions for each case. If you are not checking a game control while in a
4601 // mission, you should probably be using game_check_key() instead.
4606 if (!os_foreground()) {
4611 // If we're in a single player game, pause it.
4612 if (!(Game_mode & GM_MULTIPLAYER)){
4613 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4614 game_process_pause_key();
4622 demo_maybe_show_trailer(k);
4625 // Move the mouse cursor with the joystick.
4626 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4627 // Move the mouse cursor with the joystick
4631 joy_get_pos( &jx, &jy, &jz, &jr );
4633 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4634 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4637 mouse_get_real_pos( &mx, &my );
4638 mouse_set_pos( mx+dx, my+dy );
4643 m = mouse_down(MOUSE_LEFT_BUTTON);
4645 if ( j != Joymouse_button_status ) {
4646 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4647 Joymouse_button_status = j;
4649 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4650 } else if ( (!j) && (m) ) {
4651 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4656 // if we should be ignoring keys because of some multiplayer situations
4657 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4661 // If a popup is running, don't process all the Fn keys
4662 if( popup_active() ) {
4666 state = gameseq_get_state();
4668 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4671 case KEY_DEBUGGED + KEY_BACKSP:
4676 launch_context_help();
4681 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4683 // don't allow f2 while warping out in multiplayer
4684 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4689 case GS_STATE_INITIAL_PLAYER_SELECT:
4690 case GS_STATE_OPTIONS_MENU:
4691 case GS_STATE_HUD_CONFIG:
4692 case GS_STATE_CONTROL_CONFIG:
4693 case GS_STATE_DEATH_DIED:
4694 case GS_STATE_DEATH_BLEW_UP:
4695 case GS_STATE_VIEW_MEDALS:
4699 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4706 // hotkey selection screen -- only valid from briefing and beyond.
4709 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) ) {
4710 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4716 case KEY_DEBUGGED + KEY_F3:
4717 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4720 case KEY_DEBUGGED + KEY_F4:
4721 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4725 if(Game_mode & GM_MULTIPLAYER){
4726 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4727 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4731 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4732 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4738 case KEY_ESC | KEY_SHIFTED:
4739 // make sure to quit properly out of multiplayer
4740 if(Game_mode & GM_MULTIPLAYER){
4741 multi_quit_game(PROMPT_NONE);
4744 gameseq_post_event( GS_EVENT_QUIT_GAME );
4749 case KEY_DEBUGGED + KEY_P:
4752 case KEY_PRINT_SCRN:
4754 static int counter = 0;
4759 sprintf( tmp_name, NOX("screen%02d"), counter );
4761 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4762 gr_print_screen(tmp_name);
4770 case KEY_SHIFTED | KEY_ENTER: {
4772 #if !defined(NDEBUG)
4774 if ( Game_mode & GM_NORMAL ){
4778 // if we're in multiplayer mode, do some special networking
4779 if(Game_mode & GM_MULTIPLAYER){
4780 debug_console(game_do_dc_networking);
4787 if ( Game_mode & GM_NORMAL )
4801 gameseq_post_event(GS_EVENT_QUIT_GAME);
4804 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4807 void camera_set_position( vector *pos )
4812 void camera_set_orient( matrix *orient )
4814 Camera_orient = *orient;
4817 void camera_set_velocity( vector *vel, int instantaneous )
4819 Camera_desired_velocity.x = 0.0f;
4820 Camera_desired_velocity.y = 0.0f;
4821 Camera_desired_velocity.z = 0.0f;
4823 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4824 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4825 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4827 if ( instantaneous ) {
4828 Camera_velocity = Camera_desired_velocity;
4836 vector new_vel, delta_pos;
4838 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4839 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4840 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4842 Camera_velocity = new_vel;
4844 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4846 vm_vec_add2( &Camera_pos, &delta_pos );
4848 float ot = Camera_time+0.0f;
4850 Camera_time += flFrametime;
4852 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4855 tmp.z = 4.739f; // always go this fast forward.
4857 // pick x and y velocities so they are always on a
4858 // circle with a 25 m radius.
4860 float tmp_angle = frand()*PI2;
4862 tmp.x = 22.0f * (float)sin(tmp_angle);
4863 tmp.y = -22.0f * (float)cos(tmp_angle);
4865 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4867 //mprintf(( "Changing velocity!\n" ));
4868 camera_set_velocity( &tmp, 0 );
4871 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4872 vector tmp = { 0.0f, 0.0f, 0.0f };
4873 camera_set_velocity( &tmp, 0 );
4878 void end_demo_campaign_do()
4880 #if defined(FS2_DEMO)
4881 // show upsell screens
4882 demo_upsell_show_screens();
4883 #elif defined(OEM_BUILD)
4884 // show oem upsell screens
4885 oem_upsell_show_screens();
4888 // drop into main hall
4889 gameseq_post_event( GS_EVENT_MAIN_MENU );
4892 // All code to process events. This is the only place
4893 // that you should change the state of the game.
4894 void game_process_event( int current_state, int event )
4896 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4899 case GS_EVENT_SIMULATOR_ROOM:
4900 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4903 case GS_EVENT_MAIN_MENU:
4904 gameseq_set_state(GS_STATE_MAIN_MENU);
4907 case GS_EVENT_OPTIONS_MENU:
4908 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4911 case GS_EVENT_BARRACKS_MENU:
4912 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4915 case GS_EVENT_TECH_MENU:
4916 gameseq_set_state(GS_STATE_TECH_MENU);
4919 case GS_EVENT_TRAINING_MENU:
4920 gameseq_set_state(GS_STATE_TRAINING_MENU);
4923 case GS_EVENT_START_GAME:
4924 Select_default_ship = 0;
4925 Player_multi_died_check = -1;
4926 gameseq_set_state(GS_STATE_CMD_BRIEF);
4929 case GS_EVENT_START_BRIEFING:
4930 gameseq_set_state(GS_STATE_BRIEFING);
4933 case GS_EVENT_DEBRIEF:
4934 // did we end the campaign in the main freespace 2 single player campaign?
4935 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4936 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4938 gameseq_set_state(GS_STATE_DEBRIEF);
4941 Player_multi_died_check = -1;
4944 case GS_EVENT_SHIP_SELECTION:
4945 gameseq_set_state( GS_STATE_SHIP_SELECT );
4948 case GS_EVENT_WEAPON_SELECTION:
4949 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4952 case GS_EVENT_ENTER_GAME:
4954 // maybe start recording a demo
4956 demo_start_record("test.fsd");
4960 if (Game_mode & GM_MULTIPLAYER) {
4961 // if we're respawning, make sure we change the view mode so that the hud shows up
4962 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4966 gameseq_set_state(GS_STATE_GAME_PLAY);
4968 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4971 Player_multi_died_check = -1;
4973 // clear multiplayer button info
4974 extern button_info Multi_ship_status_bi;
4975 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4977 Start_time = f2fl(timer_get_approx_seconds());
4979 mprintf(("Entering game at time = %7.3f\n", Start_time));
4983 case GS_EVENT_START_GAME_QUICK:
4984 Select_default_ship = 1;
4985 gameseq_post_event(GS_EVENT_ENTER_GAME);
4989 case GS_EVENT_END_GAME:
4990 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4991 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4992 gameseq_set_state(GS_STATE_MAIN_MENU);
4997 Player_multi_died_check = -1;
5000 case GS_EVENT_QUIT_GAME:
5001 main_hall_stop_music();
5002 main_hall_stop_ambient();
5003 gameseq_set_state(GS_STATE_QUIT_GAME);
5005 Player_multi_died_check = -1;
5008 case GS_EVENT_GAMEPLAY_HELP:
5009 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5012 case GS_EVENT_PAUSE_GAME:
5013 gameseq_push_state(GS_STATE_GAME_PAUSED);
5016 case GS_EVENT_DEBUG_PAUSE_GAME:
5017 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5020 case GS_EVENT_TRAINING_PAUSE:
5021 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5024 case GS_EVENT_PREVIOUS_STATE:
5025 gameseq_pop_state();
5028 case GS_EVENT_TOGGLE_FULLSCREEN:
5029 #ifndef HARDWARE_ONLY
5031 if ( gr_screen.mode == GR_SOFTWARE ) {
5032 gr_init( GR_640, GR_DIRECTDRAW );
5033 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5034 gr_init( GR_640, GR_SOFTWARE );
5040 case GS_EVENT_TOGGLE_GLIDE:
5042 if ( gr_screen.mode != GR_GLIDE ) {
5043 gr_init( GR_640, GR_GLIDE );
5045 gr_init( GR_640, GR_SOFTWARE );
5050 case GS_EVENT_LOAD_MISSION_MENU:
5051 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5054 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5055 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5058 case GS_EVENT_HUD_CONFIG:
5059 gameseq_push_state( GS_STATE_HUD_CONFIG );
5062 case GS_EVENT_CONTROL_CONFIG:
5063 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5066 case GS_EVENT_DEATH_DIED:
5067 gameseq_set_state( GS_STATE_DEATH_DIED );
5070 case GS_EVENT_DEATH_BLEW_UP:
5071 if ( current_state == GS_STATE_DEATH_DIED ) {
5072 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5073 event_music_player_death();
5075 // multiplayer clients set their extra check here
5076 if(Game_mode & GM_MULTIPLAYER){
5077 // set the multi died absolute last chance check
5078 Player_multi_died_check = time(NULL);
5081 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5085 case GS_EVENT_NEW_CAMPAIGN:
5086 if (!mission_load_up_campaign()){
5087 readyroom_continue_campaign();
5090 Player_multi_died_check = -1;
5093 case GS_EVENT_CAMPAIGN_CHEAT:
5094 if (!mission_load_up_campaign()){
5096 // bash campaign value
5097 extern char Main_hall_campaign_cheat[512];
5100 // look for the mission
5101 for(idx=0; idx<Campaign.num_missions; idx++){
5102 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5103 Campaign.next_mission = idx;
5104 Campaign.prev_mission = idx - 1;
5111 readyroom_continue_campaign();
5114 Player_multi_died_check = -1;
5117 case GS_EVENT_CAMPAIGN_ROOM:
5118 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5121 case GS_EVENT_CMD_BRIEF:
5122 gameseq_set_state(GS_STATE_CMD_BRIEF);
5125 case GS_EVENT_RED_ALERT:
5126 gameseq_set_state(GS_STATE_RED_ALERT);
5129 case GS_EVENT_CREDITS:
5130 gameseq_set_state( GS_STATE_CREDITS );
5133 case GS_EVENT_VIEW_MEDALS:
5134 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5137 case GS_EVENT_SHOW_GOALS:
5138 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5141 case GS_EVENT_HOTKEY_SCREEN:
5142 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5145 // multiplayer stuff follow these comments
5147 case GS_EVENT_MULTI_JOIN_GAME:
5148 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5151 case GS_EVENT_MULTI_HOST_SETUP:
5152 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5155 case GS_EVENT_MULTI_CLIENT_SETUP:
5156 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5159 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5160 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5163 case GS_EVENT_MULTI_STD_WAIT:
5164 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5167 case GS_EVENT_STANDALONE_MAIN:
5168 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5171 case GS_EVENT_MULTI_PAUSE:
5172 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5175 case GS_EVENT_INGAME_PRE_JOIN:
5176 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5179 case GS_EVENT_EVENT_DEBUG:
5180 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5183 // Start a warpout where player automatically goes 70 no matter what
5184 // and can't cancel out of it.
5185 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5186 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5188 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5189 Player->saved_viewer_mode = Viewer_mode;
5190 Player->control_mode = PCM_WARPOUT_STAGE1;
5191 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5192 Warpout_time = 0.0f; // Start timer!
5195 case GS_EVENT_PLAYER_WARPOUT_START:
5196 if ( Player->control_mode != PCM_NORMAL ) {
5197 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5199 Player->saved_viewer_mode = Viewer_mode;
5200 Player->control_mode = PCM_WARPOUT_STAGE1;
5201 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5202 Warpout_time = 0.0f; // Start timer!
5203 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5207 case GS_EVENT_PLAYER_WARPOUT_STOP:
5208 if ( Player->control_mode != PCM_NORMAL ) {
5209 if ( !Warpout_forced ) { // cannot cancel forced warpout
5210 Player->control_mode = PCM_NORMAL;
5211 Viewer_mode = Player->saved_viewer_mode;
5212 hud_subspace_notify_abort();
5213 mprintf(( "Player put back to normal mode.\n" ));
5214 if ( Warpout_sound > -1 ) {
5215 snd_stop( Warpout_sound );
5222 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5223 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5224 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5225 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5227 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5228 shipfx_warpout_start( Player_obj );
5229 Player->control_mode = PCM_WARPOUT_STAGE2;
5230 Player->saved_viewer_mode = Viewer_mode;
5231 Viewer_mode |= VM_WARP_CHASE;
5233 vector tmp = Player_obj->pos;
5235 ship_get_eye( &tmp, &tmp_m, Player_obj );
5236 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5237 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5238 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5240 camera_set_position( &tmp );
5241 camera_set_orient( &Player_obj->orient );
5242 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5244 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5245 camera_set_velocity( &tmp_vel, 1);
5249 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5250 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5251 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5252 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5254 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5255 Player->control_mode = PCM_WARPOUT_STAGE3;
5259 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5260 mprintf(( "Player warped out. Going to debriefing!\n" ));
5261 Player->control_mode = PCM_NORMAL;
5262 Viewer_mode = Player->saved_viewer_mode;
5265 // we have a special debriefing screen for multiplayer furballs
5266 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5267 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5269 // do the normal debriefing for all other situations
5271 gameseq_post_event(GS_EVENT_DEBRIEF);
5275 case GS_EVENT_STANDALONE_POSTGAME:
5276 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5279 case GS_EVENT_INITIAL_PLAYER_SELECT:
5280 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5283 case GS_EVENT_GAME_INIT:
5284 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5285 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5287 // see if the command line option has been set to use the last pilot, and act acoordingly
5288 if( player_select_get_last_pilot() ) {
5289 // always enter the main menu -- do the automatic network startup stuff elsewhere
5290 // so that we still have valid checks for networking modes, etc.
5291 gameseq_set_state(GS_STATE_MAIN_MENU);
5293 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5298 case GS_EVENT_MULTI_MISSION_SYNC:
5299 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5302 case GS_EVENT_MULTI_START_GAME:
5303 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5306 case GS_EVENT_MULTI_HOST_OPTIONS:
5307 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5310 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5311 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5314 case GS_EVENT_TEAM_SELECT:
5315 gameseq_set_state(GS_STATE_TEAM_SELECT);
5318 case GS_EVENT_END_CAMPAIGN:
5319 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5322 case GS_EVENT_END_DEMO:
5323 gameseq_set_state(GS_STATE_END_DEMO);
5326 case GS_EVENT_LOOP_BRIEF:
5327 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5336 // Called when a state is being left.
5337 // The current state is still at old_state, but as soon as
5338 // this function leaves, then the current state will become
5339 // new state. You should never try to change the state
5340 // in here... if you think you need to, you probably really
5341 // need to post an event, not change the state.
5342 void game_leave_state( int old_state, int new_state )
5344 int end_mission = 1;
5346 switch (new_state) {
5347 case GS_STATE_GAME_PAUSED:
5348 case GS_STATE_DEBUG_PAUSED:
5349 case GS_STATE_OPTIONS_MENU:
5350 case GS_STATE_CONTROL_CONFIG:
5351 case GS_STATE_MISSION_LOG_SCROLLBACK:
5352 case GS_STATE_DEATH_DIED:
5353 case GS_STATE_SHOW_GOALS:
5354 case GS_STATE_HOTKEY_SCREEN:
5355 case GS_STATE_MULTI_PAUSED:
5356 case GS_STATE_TRAINING_PAUSED:
5357 case GS_STATE_EVENT_DEBUG:
5358 case GS_STATE_GAMEPLAY_HELP:
5359 end_mission = 0; // these events shouldn't end a mission
5363 switch (old_state) {
5364 case GS_STATE_BRIEFING:
5365 brief_stop_voices();
5366 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5367 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5368 && (new_state != GS_STATE_TEAM_SELECT) ){
5369 common_select_close();
5370 if ( new_state == GS_STATE_MAIN_MENU ) {
5371 freespace_stop_mission();
5375 // COMMAND LINE OPTION
5376 if (Cmdline_multi_stream_chat_to_file){
5377 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5378 cfclose(Multi_chat_stream);
5382 case GS_STATE_DEBRIEF:
5383 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5388 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5389 multi_df_debrief_close();
5392 case GS_STATE_LOAD_MISSION_MENU:
5393 mission_load_menu_close();
5396 case GS_STATE_SIMULATOR_ROOM:
5400 case GS_STATE_CAMPAIGN_ROOM:
5401 campaign_room_close();
5404 case GS_STATE_CMD_BRIEF:
5405 if (new_state == GS_STATE_OPTIONS_MENU) {
5410 if (new_state == GS_STATE_MAIN_MENU)
5411 freespace_stop_mission();
5416 case GS_STATE_RED_ALERT:
5420 case GS_STATE_SHIP_SELECT:
5421 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5422 new_state != GS_STATE_HOTKEY_SCREEN &&
5423 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5424 common_select_close();
5425 if ( new_state == GS_STATE_MAIN_MENU ) {
5426 freespace_stop_mission();
5431 case GS_STATE_WEAPON_SELECT:
5432 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5433 new_state != GS_STATE_HOTKEY_SCREEN &&
5434 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5435 common_select_close();
5436 if ( new_state == GS_STATE_MAIN_MENU ) {
5437 freespace_stop_mission();
5442 case GS_STATE_TEAM_SELECT:
5443 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5444 new_state != GS_STATE_HOTKEY_SCREEN &&
5445 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5446 common_select_close();
5447 if ( new_state == GS_STATE_MAIN_MENU ) {
5448 freespace_stop_mission();
5453 case GS_STATE_MAIN_MENU:
5454 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5461 case GS_STATE_OPTIONS_MENU:
5462 //game_start_time();
5463 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5464 multi_join_clear_game_list();
5466 options_menu_close();
5469 case GS_STATE_BARRACKS_MENU:
5470 if(new_state != GS_STATE_VIEW_MEDALS){
5475 case GS_STATE_MISSION_LOG_SCROLLBACK:
5476 hud_scrollback_close();
5479 case GS_STATE_TRAINING_MENU:
5480 training_menu_close();
5483 case GS_STATE_GAME_PLAY:
5484 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5485 player_save_target_and_weapon_link_prefs();
5486 game_stop_looped_sounds();
5489 sound_env_disable();
5490 joy_ff_stop_effects();
5492 // stop game time under certain conditions
5493 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5498 // shut down any recording or playing demos
5503 // when in multiplayer and going back to the main menu, send a leave game packet
5504 // right away (before calling stop mission). stop_mission was taking to long to
5505 // close mission down and I want people to get notified ASAP.
5506 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5507 multi_quit_game(PROMPT_NONE);
5510 freespace_stop_mission();
5511 Game_time_compression = F1_0;
5515 case GS_STATE_TECH_MENU:
5519 case GS_STATE_TRAINING_PAUSED:
5520 Training_num_lines = 0;
5521 // fall through to GS_STATE_GAME_PAUSED
5523 case GS_STATE_GAME_PAUSED:
5525 if ( end_mission ) {
5530 case GS_STATE_DEBUG_PAUSED:
5533 pause_debug_close();
5537 case GS_STATE_HUD_CONFIG:
5541 // join/start a game
5542 case GS_STATE_MULTI_JOIN_GAME:
5543 if(new_state != GS_STATE_OPTIONS_MENU){
5544 multi_join_game_close();
5548 case GS_STATE_MULTI_HOST_SETUP:
5549 case GS_STATE_MULTI_CLIENT_SETUP:
5550 // if this is just the host going into the options screen, don't do anything
5551 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5555 // close down the proper state
5556 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5557 multi_create_game_close();
5559 multi_game_client_setup_close();
5562 // COMMAND LINE OPTION
5563 if (Cmdline_multi_stream_chat_to_file){
5564 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5565 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5566 cfclose(Multi_chat_stream);
5571 case GS_STATE_CONTROL_CONFIG:
5572 control_config_close();
5575 case GS_STATE_DEATH_DIED:
5576 Game_mode &= ~GM_DEAD_DIED;
5578 // early end while respawning or blowing up in a multiplayer game
5579 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5581 freespace_stop_mission();
5585 case GS_STATE_DEATH_BLEW_UP:
5586 Game_mode &= ~GM_DEAD_BLEW_UP;
5588 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5589 // to determine if I should do anything.
5590 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5592 freespace_stop_mission();
5595 // if we are not respawing as an observer or as a player, our new state will not
5596 // be gameplay state.
5597 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5598 game_stop_time(); // hasn't been called yet!!
5599 freespace_stop_mission();
5605 case GS_STATE_CREDITS:
5609 case GS_STATE_VIEW_MEDALS:
5613 case GS_STATE_SHOW_GOALS:
5614 mission_show_goals_close();
5617 case GS_STATE_HOTKEY_SCREEN:
5618 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5619 mission_hotkey_close();
5623 case GS_STATE_MULTI_MISSION_SYNC:
5624 // if we're moving into the options menu, don't do anything
5625 if(new_state == GS_STATE_OPTIONS_MENU){
5629 Assert( Game_mode & GM_MULTIPLAYER );
5631 if ( new_state == GS_STATE_GAME_PLAY ){
5632 // palette_restore_palette();
5634 // change a couple of flags to indicate our state!!!
5635 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5636 send_netplayer_update_packet();
5638 // set the game mode
5639 Game_mode |= GM_IN_MISSION;
5643 case GS_STATE_VIEW_CUTSCENES:
5644 cutscenes_screen_close();
5647 case GS_STATE_MULTI_STD_WAIT:
5648 multi_standalone_wait_close();
5651 case GS_STATE_STANDALONE_MAIN:
5652 standalone_main_close();
5653 if(new_state == GS_STATE_MULTI_STD_WAIT){
5654 init_multiplayer_stats();
5658 case GS_STATE_MULTI_PAUSED:
5659 // if ( end_mission ){
5664 case GS_STATE_INGAME_PRE_JOIN:
5665 multi_ingame_select_close();
5668 case GS_STATE_STANDALONE_POSTGAME:
5669 multi_standalone_postgame_close();
5672 case GS_STATE_INITIAL_PLAYER_SELECT:
5673 player_select_close();
5676 case GS_STATE_MULTI_START_GAME:
5677 multi_start_game_close();
5680 case GS_STATE_MULTI_HOST_OPTIONS:
5681 multi_host_options_close();
5684 case GS_STATE_END_OF_CAMPAIGN:
5685 mission_campaign_end_close();
5688 case GS_STATE_LOOP_BRIEF:
5694 // Called when a state is being entered.
5695 // The current state is set to the state we're entering at
5696 // this point, and old_state is set to the state we're coming
5697 // from. You should never try to change the state
5698 // in here... if you think you need to, you probably really
5699 // need to post an event, not change the state.
5701 void game_enter_state( int old_state, int new_state )
5703 switch (new_state) {
5704 case GS_STATE_MAIN_MENU:
5705 // in multiplayer mode, be sure that we are not doing networking anymore.
5706 if ( Game_mode & GM_MULTIPLAYER ) {
5707 Assert( Net_player != NULL );
5708 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5711 Game_time_compression = F1_0;
5713 // determine which ship this guy is currently based on
5714 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5717 if (Player->on_bastion) {
5725 case GS_STATE_BRIEFING:
5726 main_hall_stop_music();
5727 main_hall_stop_ambient();
5729 if (Game_mode & GM_NORMAL) {
5730 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5731 // MWA: or from options or hotkey screens
5732 // JH: or if the command brief state already did this
5733 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5734 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5735 && (old_state != GS_STATE_CMD_BRIEF) ) {
5736 if ( !game_start_mission() ) // this should put us into a new state on failure!
5740 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5741 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5742 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5744 Game_time_compression = F1_0;
5746 if ( red_alert_mission() ) {
5747 gameseq_post_event(GS_EVENT_RED_ALERT);
5754 case GS_STATE_DEBRIEF:
5755 game_stop_looped_sounds();
5756 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5757 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5762 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5763 multi_df_debrief_init();
5766 case GS_STATE_LOAD_MISSION_MENU:
5767 mission_load_menu_init();
5770 case GS_STATE_SIMULATOR_ROOM:
5774 case GS_STATE_CAMPAIGN_ROOM:
5775 campaign_room_init();
5778 case GS_STATE_RED_ALERT:
5779 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5783 case GS_STATE_CMD_BRIEF: {
5784 int team_num = 0; // team number used as index for which cmd brief to use.
5786 if (old_state == GS_STATE_OPTIONS_MENU) {
5790 main_hall_stop_music();
5791 main_hall_stop_ambient();
5793 if (Game_mode & GM_NORMAL) {
5794 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5795 // MWA: or from options or hotkey screens
5796 // JH: or if the command brief state already did this
5797 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5798 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5799 if ( !game_start_mission() ) // this should put us into a new state on failure!
5804 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5805 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5806 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5808 cmd_brief_init(team_num);
5814 case GS_STATE_SHIP_SELECT:
5818 case GS_STATE_WEAPON_SELECT:
5819 weapon_select_init();
5822 case GS_STATE_TEAM_SELECT:
5826 case GS_STATE_GAME_PAUSED:
5831 case GS_STATE_DEBUG_PAUSED:
5832 // game_stop_time();
5833 // os_set_title("FreeSpace - PAUSED");
5836 case GS_STATE_TRAINING_PAUSED:
5843 case GS_STATE_OPTIONS_MENU:
5845 options_menu_init();
5848 case GS_STATE_GAME_PLAY:
5849 // coming from the gameplay state or the main menu, we might need to load the mission
5850 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5851 if ( !game_start_mission() ) // this should put us into a new state.
5856 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5857 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5858 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5859 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5860 (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) ) {
5861 // JAS: Used to do all paging here.
5865 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5869 main_hall_stop_music();
5870 main_hall_stop_ambient();
5871 event_music_first_pattern(); // start the first pattern
5874 // special code that restores player ship selection and weapons loadout when doing a quick start
5875 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5876 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5877 wss_direct_restore_loadout();
5881 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5882 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5883 event_music_first_pattern(); // start the first pattern
5886 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5887 event_music_first_pattern(); // start the first pattern
5889 player_restore_target_and_weapon_link_prefs();
5891 Game_mode |= GM_IN_MISSION;
5894 // required to truely make mouse deltas zeroed in debug mouse code
5895 void mouse_force_pos(int x, int y);
5896 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5901 // only start time if in single player, or coming from multi wait state
5904 (Game_mode & GM_NORMAL) &&
5905 (old_state != GS_STATE_VIEW_CUTSCENES)
5907 (Game_mode & GM_MULTIPLAYER) && (
5908 (old_state == GS_STATE_MULTI_PAUSED) ||
5909 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5915 // when coming from the multi paused state, reset the timestamps
5916 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5917 multi_reset_timestamps();
5920 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5921 // initialize all object update details
5922 multi_oo_gameplay_init();
5925 // under certain circumstances, the server should reset the object update rate limiting stuff
5926 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5927 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5929 // reinitialize the rate limiting system for all clients
5930 multi_oo_rate_init_all();
5933 // multiplayer clients should always re-initialize their control info rate limiting system
5934 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5935 multi_oo_rate_init_all();
5939 if(Game_mode & GM_MULTIPLAYER){
5940 multi_ping_reset_players();
5943 Game_subspace_effect = 0;
5944 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5945 Game_subspace_effect = 1;
5946 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5947 game_start_subspace_ambient_sound();
5951 sound_env_set(&Game_sound_env);
5952 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5954 // clear multiplayer button info i
5955 extern button_info Multi_ship_status_bi;
5956 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5959 case GS_STATE_HUD_CONFIG:
5963 case GS_STATE_MULTI_JOIN_GAME:
5964 multi_join_clear_game_list();
5966 if (old_state != GS_STATE_OPTIONS_MENU) {
5967 multi_join_game_init();
5972 case GS_STATE_MULTI_HOST_SETUP:
5973 // don't reinitialize if we're coming back from the host options screen
5974 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5975 multi_create_game_init();
5980 case GS_STATE_MULTI_CLIENT_SETUP:
5981 if (old_state != GS_STATE_OPTIONS_MENU) {
5982 multi_game_client_setup_init();
5987 case GS_STATE_CONTROL_CONFIG:
5988 control_config_init();
5991 case GS_STATE_TECH_MENU:
5995 case GS_STATE_BARRACKS_MENU:
5996 if(old_state != GS_STATE_VIEW_MEDALS){
6001 case GS_STATE_MISSION_LOG_SCROLLBACK:
6002 hud_scrollback_init();
6005 case GS_STATE_DEATH_DIED:
6006 Player_died_time = timestamp(10);
6008 if(!(Game_mode & GM_MULTIPLAYER)){
6009 player_show_death_message();
6011 Game_mode |= GM_DEAD_DIED;
6014 case GS_STATE_DEATH_BLEW_UP:
6015 if ( !popupdead_is_active() ) {
6016 Player_ai->target_objnum = -1;
6019 // stop any local EMP effect
6022 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6023 Game_mode |= GM_DEAD_BLEW_UP;
6024 Show_viewing_from_self = 0;
6026 // timestamp how long we should wait before displaying the died popup
6027 if ( !popupdead_is_active() ) {
6028 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6032 case GS_STATE_GAMEPLAY_HELP:
6033 gameplay_help_init();
6036 case GS_STATE_CREDITS:
6037 main_hall_stop_music();
6038 main_hall_stop_ambient();
6042 case GS_STATE_VIEW_MEDALS:
6043 medal_main_init(Player);
6046 case GS_STATE_SHOW_GOALS:
6047 mission_show_goals_init();
6050 case GS_STATE_HOTKEY_SCREEN:
6051 mission_hotkey_init();
6054 case GS_STATE_MULTI_MISSION_SYNC:
6055 // if we're coming from the options screen, don't do any
6056 if(old_state == GS_STATE_OPTIONS_MENU){
6060 switch(Multi_sync_mode){
6061 case MULTI_SYNC_PRE_BRIEFING:
6062 // if moving from game forming to the team select state
6065 case MULTI_SYNC_POST_BRIEFING:
6066 // if moving from briefing into the mission itself
6069 // tell everyone that we're now loading data
6070 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6071 send_netplayer_update_packet();
6073 // JAS: Used to do all paging here!!!!
6075 Net_player->state = NETPLAYER_STATE_WAITING;
6076 send_netplayer_update_packet();
6078 Game_time_compression = F1_0;
6080 case MULTI_SYNC_INGAME:
6086 case GS_STATE_VIEW_CUTSCENES:
6087 cutscenes_screen_init();
6090 case GS_STATE_MULTI_STD_WAIT:
6091 multi_standalone_wait_init();
6094 case GS_STATE_STANDALONE_MAIN:
6095 // don't initialize if we're coming from one of these 2 states unless there are no
6096 // players left (reset situation)
6097 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6098 standalone_main_init();
6102 case GS_STATE_MULTI_PAUSED:
6106 case GS_STATE_INGAME_PRE_JOIN:
6107 multi_ingame_select_init();
6110 case GS_STATE_STANDALONE_POSTGAME:
6111 multi_standalone_postgame_init();
6114 case GS_STATE_INITIAL_PLAYER_SELECT:
6115 player_select_init();
6118 case GS_STATE_MULTI_START_GAME:
6119 multi_start_game_init();
6122 case GS_STATE_MULTI_HOST_OPTIONS:
6123 multi_host_options_init();
6126 case GS_STATE_END_OF_CAMPAIGN:
6127 mission_campaign_end_init();
6130 case GS_STATE_LOOP_BRIEF:
6137 // do stuff that may need to be done regardless of state
6138 void game_do_state_common(int state,int no_networking)
6140 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6141 snd_do_frame(); // update sound system
6142 event_music_do_frame(); // music needs to play across many states
6144 multi_log_process();
6146 if (no_networking) {
6150 // maybe do a multiplayer frame based on game mode and state type
6151 if (Game_mode & GM_MULTIPLAYER) {
6153 case GS_STATE_OPTIONS_MENU:
6154 case GS_STATE_GAMEPLAY_HELP:
6155 case GS_STATE_HOTKEY_SCREEN:
6156 case GS_STATE_HUD_CONFIG:
6157 case GS_STATE_CONTROL_CONFIG:
6158 case GS_STATE_MISSION_LOG_SCROLLBACK:
6159 case GS_STATE_SHOW_GOALS:
6160 case GS_STATE_VIEW_CUTSCENES:
6161 case GS_STATE_EVENT_DEBUG:
6162 multi_maybe_do_frame();
6166 game_do_networking();
6170 // Called once a frame.
6171 // You should never try to change the state
6172 // in here... if you think you need to, you probably really
6173 // need to post an event, not change the state.
6174 int Game_do_state_should_skip = 0;
6175 void game_do_state(int state)
6177 // always lets the do_state_common() function determine if the state should be skipped
6178 Game_do_state_should_skip = 0;
6180 // legal to set the should skip state anywhere in this function
6181 game_do_state_common(state); // do stuff that may need to be done regardless of state
6183 if(Game_do_state_should_skip){
6188 case GS_STATE_MAIN_MENU:
6189 game_set_frametime(GS_STATE_MAIN_MENU);
6190 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6193 main_hall_do(flFrametime);
6197 case GS_STATE_OPTIONS_MENU:
6198 game_set_frametime(GS_STATE_OPTIONS_MENU);
6199 options_menu_do_frame(flFrametime);
6202 case GS_STATE_BARRACKS_MENU:
6203 game_set_frametime(GS_STATE_BARRACKS_MENU);
6204 barracks_do_frame(flFrametime);
6207 case GS_STATE_TRAINING_MENU:
6208 game_set_frametime(GS_STATE_TRAINING_MENU);
6209 training_menu_do_frame(flFrametime);
6212 case GS_STATE_TECH_MENU:
6213 game_set_frametime(GS_STATE_TECH_MENU);
6214 techroom_do_frame(flFrametime);
6217 case GS_STATE_GAMEPLAY_HELP:
6218 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6219 gameplay_help_do_frame(flFrametime);
6222 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6226 case GS_STATE_GAME_PAUSED:
6230 case GS_STATE_DEBUG_PAUSED:
6232 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6237 case GS_STATE_TRAINING_PAUSED:
6238 game_training_pause_do();
6241 case GS_STATE_LOAD_MISSION_MENU:
6242 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6243 mission_load_menu_do();
6246 case GS_STATE_BRIEFING:
6247 game_set_frametime(GS_STATE_BRIEFING);
6248 brief_do_frame(flFrametime);
6251 case GS_STATE_DEBRIEF:
6252 game_set_frametime(GS_STATE_DEBRIEF);
6253 debrief_do_frame(flFrametime);
6256 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6257 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6258 multi_df_debrief_do();
6261 case GS_STATE_SHIP_SELECT:
6262 game_set_frametime(GS_STATE_SHIP_SELECT);
6263 ship_select_do(flFrametime);
6266 case GS_STATE_WEAPON_SELECT:
6267 game_set_frametime(GS_STATE_WEAPON_SELECT);
6268 weapon_select_do(flFrametime);
6271 case GS_STATE_MISSION_LOG_SCROLLBACK:
6272 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6273 hud_scrollback_do_frame(flFrametime);
6276 case GS_STATE_HUD_CONFIG:
6277 game_set_frametime(GS_STATE_HUD_CONFIG);
6278 hud_config_do_frame(flFrametime);
6281 case GS_STATE_MULTI_JOIN_GAME:
6282 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6283 multi_join_game_do_frame();
6286 case GS_STATE_MULTI_HOST_SETUP:
6287 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6288 multi_create_game_do();
6291 case GS_STATE_MULTI_CLIENT_SETUP:
6292 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6293 multi_game_client_setup_do_frame();
6296 case GS_STATE_CONTROL_CONFIG:
6297 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6298 control_config_do_frame(flFrametime);
6301 case GS_STATE_DEATH_DIED:
6305 case GS_STATE_DEATH_BLEW_UP:
6309 case GS_STATE_SIMULATOR_ROOM:
6310 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6311 sim_room_do_frame(flFrametime);
6314 case GS_STATE_CAMPAIGN_ROOM:
6315 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6316 campaign_room_do_frame(flFrametime);
6319 case GS_STATE_RED_ALERT:
6320 game_set_frametime(GS_STATE_RED_ALERT);
6321 red_alert_do_frame(flFrametime);
6324 case GS_STATE_CMD_BRIEF:
6325 game_set_frametime(GS_STATE_CMD_BRIEF);
6326 cmd_brief_do_frame(flFrametime);
6329 case GS_STATE_CREDITS:
6330 game_set_frametime(GS_STATE_CREDITS);
6331 credits_do_frame(flFrametime);
6334 case GS_STATE_VIEW_MEDALS:
6335 game_set_frametime(GS_STATE_VIEW_MEDALS);
6339 case GS_STATE_SHOW_GOALS:
6340 game_set_frametime(GS_STATE_SHOW_GOALS);
6341 mission_show_goals_do_frame(flFrametime);
6344 case GS_STATE_HOTKEY_SCREEN:
6345 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6346 mission_hotkey_do_frame(flFrametime);
6349 case GS_STATE_VIEW_CUTSCENES:
6350 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6351 cutscenes_screen_do_frame();
6354 case GS_STATE_MULTI_STD_WAIT:
6355 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6356 multi_standalone_wait_do();
6359 case GS_STATE_STANDALONE_MAIN:
6360 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6361 standalone_main_do();
6364 case GS_STATE_MULTI_PAUSED:
6365 game_set_frametime(GS_STATE_MULTI_PAUSED);
6369 case GS_STATE_TEAM_SELECT:
6370 game_set_frametime(GS_STATE_TEAM_SELECT);
6374 case GS_STATE_INGAME_PRE_JOIN:
6375 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6376 multi_ingame_select_do();
6379 case GS_STATE_EVENT_DEBUG:
6381 game_set_frametime(GS_STATE_EVENT_DEBUG);
6382 game_show_event_debug(flFrametime);
6386 case GS_STATE_STANDALONE_POSTGAME:
6387 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6388 multi_standalone_postgame_do();
6391 case GS_STATE_INITIAL_PLAYER_SELECT:
6392 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6396 case GS_STATE_MULTI_MISSION_SYNC:
6397 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6401 case GS_STATE_MULTI_START_GAME:
6402 game_set_frametime(GS_STATE_MULTI_START_GAME);
6403 multi_start_game_do();
6406 case GS_STATE_MULTI_HOST_OPTIONS:
6407 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6408 multi_host_options_do();
6411 case GS_STATE_END_OF_CAMPAIGN:
6412 mission_campaign_end_do();
6415 case GS_STATE_END_DEMO:
6416 game_set_frametime(GS_STATE_END_DEMO);
6417 end_demo_campaign_do();
6420 case GS_STATE_LOOP_BRIEF:
6421 game_set_frametime(GS_STATE_LOOP_BRIEF);
6425 } // end switch(gs_current_state)
6429 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6430 int game_do_ram_check(int ram_in_bytes)
6432 if ( ram_in_bytes < 30*1024*1024 ) {
6433 int allowed_to_run = 1;
6434 if ( ram_in_bytes < 25*1024*1024 ) {
6439 int Freespace_total_ram_MB;
6440 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6442 if ( allowed_to_run ) {
6444 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);
6448 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6449 if ( msgbox_rval == IDCANCEL ) {
6456 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);
6458 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6469 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6470 // If so, copy it over and remove the update directory.
6471 void game_maybe_update_launcher(char *exe_dir)
6474 char src_filename[MAX_PATH];
6475 char dest_filename[MAX_PATH];
6477 strcpy(src_filename, exe_dir);
6478 strcat(src_filename, NOX("\\update\\freespace.exe"));
6480 strcpy(dest_filename, exe_dir);
6481 strcat(dest_filename, NOX("\\freespace.exe"));
6483 // see if src_filename exists
6485 fp = fopen(src_filename, "rb");
6491 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6493 // copy updated freespace.exe to freespace exe dir
6494 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6495 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 );
6499 // delete the file in the update directory
6500 DeleteFile(src_filename);
6502 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6503 char update_dir[MAX_PATH];
6504 strcpy(update_dir, exe_dir);
6505 strcat(update_dir, NOX("\\update"));
6506 RemoveDirectory(update_dir);
6512 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6516 int sub_total_destroyed = 0;
6520 // get the total for all his children
6521 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6522 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6525 // find the # of faces for this _individual_ object
6526 total = submodel_get_num_polys(model_num, sm);
6527 if(strstr(pm->submodel[sm].name, "-destroyed")){
6528 sub_total_destroyed = total;
6532 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6535 *out_total += total + sub_total;
6536 *out_destroyed_total += sub_total_destroyed;
6539 #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);
6540 void game_spew_pof_info()
6542 char *pof_list[1000];
6545 int idx, model_num, i, j;
6547 int total, root_total, model_total, destroyed_total, counted;
6551 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6553 // spew info on all the pofs
6559 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6564 for(idx=0; idx<num_files; idx++, counted++){
6565 sprintf(str, "%s.pof", pof_list[idx]);
6566 model_num = model_load(str, 0, NULL);
6568 pm = model_get(model_num);
6570 // if we have a real model
6575 // go through and print all raw submodels
6576 cfputs("RAW\n", out);
6579 for (i=0; i<pm->n_models; i++) {
6580 total = submodel_get_num_polys(model_num, i);
6582 model_total += total;
6583 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6586 sprintf(str, "Model total %d\n", model_total);
6589 // now go through and do it by LOD
6590 cfputs("BY LOD\n\n", out);
6591 for(i=0; i<pm->n_detail_levels; i++){
6592 sprintf(str, "LOD %d\n", i);
6596 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6598 destroyed_total = 0;
6599 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6600 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6603 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6606 sprintf(str, "TOTAL: %d\n", total + root_total);
6608 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6610 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6613 cfputs("------------------------------------------------------------------------\n\n", out);
6617 if(counted >= MAX_POLYGON_MODELS - 5){
6630 game_spew_pof_info();
6633 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6638 // Don't let more than one instance of Freespace run.
6639 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6641 SetForegroundWindow(hwnd);
6646 // Find out how much RAM is on this machine
6649 ms.dwLength = sizeof(MEMORYSTATUS);
6650 GlobalMemoryStatus(&ms);
6651 Freespace_total_ram = ms.dwTotalPhys;
6653 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6657 if ( ms.dwTotalVirtual < 1024 ) {
6658 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6662 if (!vm_init(24*1024*1024)) {
6663 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 );
6667 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6669 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);
6679 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6680 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6681 seem worth bothering with.
6685 lResult = RegOpenKeyEx(
6686 HKEY_LOCAL_MACHINE, // Where it is
6687 "Software\\Microsoft\\DirectX", // name of key
6688 NULL, // DWORD reserved
6689 KEY_QUERY_VALUE, // Allows all changes
6690 &hKey // Location to store key
6693 if (lResult == ERROR_SUCCESS) {
6695 DWORD dwType, dwLen;
6698 lResult = RegQueryValueEx(
6699 hKey, // Handle to key
6700 "Version", // The values name
6701 NULL, // DWORD reserved
6702 &dwType, // What kind it is
6703 (ubyte *) version, // value to set
6704 &dwLen // How many bytes to set
6707 if (lResult == ERROR_SUCCESS) {
6708 dx_version = atoi(strstr(version, ".") + 1);
6712 DWORD dwType, dwLen;
6715 lResult = RegQueryValueEx(
6716 hKey, // Handle to key
6717 "InstalledVersion", // The values name
6718 NULL, // DWORD reserved
6719 &dwType, // What kind it is
6720 (ubyte *) &val, // value to set
6721 &dwLen // How many bytes to set
6724 if (lResult == ERROR_SUCCESS) {
6732 if (dx_version < 3) {
6733 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6734 "latest version of DirectX at:\n\n"
6735 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6737 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6738 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6743 //=====================================================
6744 // Make sure we're running in the right directory.
6748 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6749 char *p = exe_dir + strlen(exe_dir);
6751 // chop off the filename
6752 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6758 if ( strlen(exe_dir) > 0 ) {
6759 SetCurrentDirectory(exe_dir);
6762 // check for updated freespace.exe
6763 game_maybe_update_launcher(exe_dir);
6771 extern void windebug_memwatch_init();
6772 windebug_memwatch_init();
6776 parse_cmdline(szCmdLine);
6778 #ifdef STANDALONE_ONLY_BUILD
6780 nprintf(("Network", "Standalone running"));
6783 nprintf(("Network", "Standalone running"));
6791 // maybe spew pof stuff
6792 if(Cmdline_spew_pof_info){
6793 game_spew_pof_info();
6798 // non-demo, non-standalone, play the intro movie
6803 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) ){
6805 #if defined(OEM_BUILD)
6806 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6808 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6809 #endif // defined(OEM_BUILD)
6814 if ( !Is_standalone ) {
6816 // release -- movies always play
6819 // 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
6821 // movie_play( NOX("intro.mve"), 0 );
6823 // debug version, movie will only play with -showmovies
6824 #elif !defined(NDEBUG)
6827 // movie_play( NOX("intro.mve"), 0);
6830 if ( Cmdline_show_movies )
6831 movie_play( NOX("intro.mve"), 0 );
6840 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6842 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6846 // only important for non THREADED mode
6849 state = gameseq_process_events();
6850 if ( state == GS_STATE_QUIT_GAME ){
6857 demo_upsell_show_screens();
6859 #elif defined(OEM_BUILD)
6860 // show upsell screens on exit
6861 oem_upsell_show_screens();
6868 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6874 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6876 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6878 // Do nothing here - RecordExceptionInfo() has already done
6879 // everything that is needed. Actually this code won't even
6880 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6881 // the __except clause.
6887 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6888 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6892 // launcher the fslauncher program on exit
6893 void game_launch_launcher_on_exit()
6897 PROCESS_INFORMATION pi;
6898 char cmd_line[2048];
6899 char original_path[1024] = "";
6901 memset( &si, 0, sizeof(STARTUPINFO) );
6905 _getcwd(original_path, 1023);
6907 // set up command line
6908 strcpy(cmd_line, original_path);
6909 strcat(cmd_line, "\\");
6910 strcat(cmd_line, LAUNCHER_FNAME);
6911 strcat(cmd_line, " -straight_to_update");
6913 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6914 cmd_line, // pointer to command line string
6915 NULL, // pointer to process security attributes
6916 NULL, // pointer to thread security attributes
6917 FALSE, // handle inheritance flag
6918 CREATE_DEFAULT_ERROR_MODE, // creation flags
6919 NULL, // pointer to new environment block
6920 NULL, // pointer to current directory name
6921 &si, // pointer to STARTUPINFO
6922 &pi // pointer to PROCESS_INFORMATION
6924 // to eliminate build warnings
6934 // This function is called when FreeSpace terminates normally.
6936 void game_shutdown(void)
6942 // don't ever flip a page on the standalone!
6943 if(!(Game_mode & GM_STANDALONE_SERVER)){
6949 // if the player has left the "player select" screen and quit the game without actually choosing
6950 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6951 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6955 // load up common multiplayer icons
6956 multi_unload_common_icons();
6958 shockwave_close(); // release any memory used by shockwave system
6959 fireball_close(); // free fireball system
6960 ship_close(); // free any memory that was allocated for the ships
6961 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6962 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6963 bm_unload_all(); // free bitmaps
6964 mission_campaign_close(); // close out the campaign stuff
6965 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6967 #ifdef MULTI_USE_LAG
6971 // the menu close functions will unload the bitmaps if they were displayed during the game
6972 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6975 training_menu_close();
6978 extern void joy_close();
6981 audiostream_close();
6983 event_music_close();
6987 // HACKITY HACK HACK
6988 // if this flag is set, we should be firing up the launcher when exiting freespace
6989 extern int Multi_update_fireup_launcher_on_exit;
6990 if(Multi_update_fireup_launcher_on_exit){
6991 game_launch_launcher_on_exit();
6995 // game_stop_looped_sounds()
6997 // This function will call the appropriate stop looped sound functions for those
6998 // modules which use looping sounds. It is not enough just to stop a looping sound
6999 // at the DirectSound level, the game is keeping track of looping sounds, and this
7000 // function is used to inform the game that looping sounds are being halted.
7002 void game_stop_looped_sounds()
7004 hud_stop_looped_locking_sounds();
7005 hud_stop_looped_engine_sounds();
7006 afterburner_stop_sounds();
7007 player_stop_looped_sounds();
7008 obj_snd_stop_all(); // stop all object-linked persistant sounds
7009 game_stop_subspace_ambient_sound();
7010 snd_stop(Radar_static_looping);
7011 Radar_static_looping = -1;
7012 snd_stop(Target_static_looping);
7013 shipfx_stop_engine_wash_sound();
7014 Target_static_looping = -1;
7017 //////////////////////////////////////////////////////////////////////////
7019 // Code for supporting an animating mouse pointer
7022 //////////////////////////////////////////////////////////////////////////
7024 typedef struct animating_obj
7033 static animating_obj Animating_mouse;
7035 // ----------------------------------------------------------------------------
7036 // init_animating_pointer()
7038 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7039 // gets properly initialized
7041 void init_animating_pointer()
7043 Animating_mouse.first_frame = -1;
7044 Animating_mouse.num_frames = 0;
7045 Animating_mouse.current_frame = -1;
7046 Animating_mouse.time = 0.0f;
7047 Animating_mouse.elapsed_time = 0.0f;
7050 // ----------------------------------------------------------------------------
7051 // load_animating_pointer()
7053 // Called at game init to load in the frames for the animating mouse pointer
7055 // input: filename => filename of animation file that holds the animation
7057 void load_animating_pointer(char *filename, int dx, int dy)
7062 init_animating_pointer();
7064 am = &Animating_mouse;
7065 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7066 if ( am->first_frame == -1 )
7067 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7068 am->current_frame = 0;
7069 am->time = am->num_frames / i2fl(fps);
7072 // ----------------------------------------------------------------------------
7073 // unload_animating_pointer()
7075 // Called at game shutdown to free the memory used to store the animation frames
7077 void unload_animating_pointer()
7082 am = &Animating_mouse;
7083 for ( i = 0; i < am->num_frames; i++ ) {
7084 Assert( (am->first_frame+i) >= 0 );
7085 bm_release(am->first_frame + i);
7088 am->first_frame = -1;
7090 am->current_frame = -1;
7093 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7094 void game_render_mouse(float frametime)
7099 // if animating cursor exists, play the next frame
7100 am = &Animating_mouse;
7101 if ( am->first_frame != -1 ) {
7102 mouse_get_pos(&mx, &my);
7103 am->elapsed_time += frametime;
7104 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7105 if ( am->current_frame >= am->num_frames ) {
7106 am->current_frame = 0;
7107 am->elapsed_time = 0.0f;
7109 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7113 // ----------------------------------------------------------------------------
7114 // game_maybe_draw_mouse()
7116 // determines whether to draw the mouse pointer at all, and what frame of
7117 // animation to use if the mouse is animating
7119 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7121 // input: frametime => elapsed frame time in seconds since last call
7123 void game_maybe_draw_mouse(float frametime)
7127 game_state = gameseq_get_state();
7129 switch ( game_state ) {
7130 case GS_STATE_GAME_PAUSED:
7131 // case GS_STATE_MULTI_PAUSED:
7132 case GS_STATE_GAME_PLAY:
7133 case GS_STATE_DEATH_DIED:
7134 case GS_STATE_DEATH_BLEW_UP:
7135 if ( popup_active() || popupdead_is_active() ) {
7147 if ( !Mouse_hidden )
7148 game_render_mouse(frametime);
7152 void game_do_training_checks()
7156 waypoint_list *wplp;
7158 if (Training_context & TRAINING_CONTEXT_SPEED) {
7159 s = (int) Player_obj->phys_info.fspeed;
7160 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7161 if (!Training_context_speed_set) {
7162 Training_context_speed_set = 1;
7163 Training_context_speed_timestamp = timestamp();
7167 Training_context_speed_set = 0;
7170 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7171 wplp = &Waypoint_lists[Training_context_path];
7172 if (wplp->count > Training_context_goal_waypoint) {
7173 i = Training_context_goal_waypoint;
7175 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7176 if (d <= Training_context_distance) {
7177 Training_context_at_waypoint = i;
7178 if (Training_context_goal_waypoint == i) {
7179 Training_context_goal_waypoint++;
7180 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7187 if (i == wplp->count)
7190 } while (i != Training_context_goal_waypoint);
7194 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7195 Players_target = Player_ai->target_objnum;
7196 Players_targeted_subsys = Player_ai->targeted_subsys;
7197 Players_target_timestamp = timestamp();
7201 /////////// Following is for event debug view screen
7205 #define EVENT_DEBUG_MAX 5000
7206 #define EVENT_DEBUG_EVENT 0x8000
7208 int Event_debug_index[EVENT_DEBUG_MAX];
7211 void game_add_event_debug_index(int n, int indent)
7213 if (ED_count < EVENT_DEBUG_MAX)
7214 Event_debug_index[ED_count++] = n | (indent << 16);
7217 void game_add_event_debug_sexp(int n, int indent)
7222 if (Sexp_nodes[n].first >= 0) {
7223 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7224 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7228 game_add_event_debug_index(n, indent);
7229 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7230 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7232 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7235 void game_event_debug_init()
7240 for (e=0; e<Num_mission_events; e++) {
7241 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7242 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7246 void game_show_event_debug(float frametime)
7250 int font_height, font_width;
7252 static int scroll_offset = 0;
7254 k = game_check_key();
7260 if (scroll_offset < 0)
7270 scroll_offset -= 20;
7271 if (scroll_offset < 0)
7276 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7280 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7286 gr_set_color_fast(&Color_bright);
7288 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7290 gr_set_color_fast(&Color_normal);
7292 gr_get_string_size(&font_width, &font_height, NOX("test"));
7293 y_max = gr_screen.max_h - font_height - 5;
7297 while (k < ED_count) {
7298 if (y_index > y_max)
7301 z = Event_debug_index[k];
7302 if (z & EVENT_DEBUG_EVENT) {
7304 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7305 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7306 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7307 Mission_events[z].repeat_count, Mission_events[z].interval);
7315 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7316 switch (Sexp_nodes[z & 0x7fff].value) {
7318 strcat(buf, NOX(" (True)"));
7322 strcat(buf, NOX(" (False)"));
7325 case SEXP_KNOWN_TRUE:
7326 strcat(buf, NOX(" (Always true)"));
7329 case SEXP_KNOWN_FALSE:
7330 strcat(buf, NOX(" (Always false)"));
7333 case SEXP_CANT_EVAL:
7334 strcat(buf, NOX(" (Can't eval)"));
7338 case SEXP_NAN_FOREVER:
7339 strcat(buf, NOX(" (Not a number)"));
7344 gr_printf(10, y_index, buf);
7345 y_index += font_height;
7358 extern int Tmap_npixels;
7360 int Tmap_num_too_big = 0;
7361 int Num_models_needing_splitting = 0;
7363 void Time_model( int modelnum )
7365 // mprintf(( "Timing ship '%s'\n", si->name ));
7367 vector eye_pos, model_pos;
7368 matrix eye_orient, model_orient;
7370 polymodel *pm = model_get( modelnum );
7372 int l = strlen(pm->filename);
7374 if ( (l == '/') || (l=='\\') || (l==':')) {
7380 char *pof_file = &pm->filename[l];
7382 int model_needs_splitting = 0;
7384 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7386 for (i=0; i<pm->n_textures; i++ ) {
7387 char filename[1024];
7390 int bmp_num = pm->original_textures[i];
7391 if ( bmp_num > -1 ) {
7392 bm_get_palette(pm->original_textures[i], pal, filename );
7394 bm_get_info( pm->original_textures[i],&w, &h );
7397 if ( (w > 512) || (h > 512) ) {
7398 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7400 model_needs_splitting++;
7403 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7407 if ( model_needs_splitting ) {
7408 Num_models_needing_splitting++;
7410 eye_orient = model_orient = vmd_identity_matrix;
7411 eye_pos = model_pos = vmd_zero_vector;
7413 eye_pos.z = -pm->rad*2.0f;
7415 vector eye_to_model;
7417 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7418 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7420 fix t1 = timer_get_fixed_seconds();
7423 ta.p = ta.b = ta.h = 0.0f;
7428 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7430 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7432 modelstats_num_polys = modelstats_num_verts = 0;
7434 while( ta.h < PI2 ) {
7437 vm_angles_2_matrix(&m1, &ta );
7438 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7445 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7447 model_clear_instance( modelnum );
7448 model_set_detail_level(0); // use highest detail level
7449 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7457 int k = key_inkey();
7458 if ( k == KEY_ESC ) {
7463 fix t2 = timer_get_fixed_seconds();
7465 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7466 //bitmaps_used_this_frame /= framecount;
7468 modelstats_num_polys /= framecount;
7469 modelstats_num_verts /= framecount;
7471 Tmap_npixels /=framecount;
7474 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7475 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 );
7476 // 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 );
7482 int Time_models = 0;
7483 DCF_BOOL( time_models, Time_models );
7485 void Do_model_timings_test()
7489 if ( !Time_models ) return;
7491 mprintf(( "Timing models!\n" ));
7495 ubyte model_used[MAX_POLYGON_MODELS];
7496 int model_id[MAX_POLYGON_MODELS];
7497 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7502 for (i=0; i<Num_ship_types; i++ ) {
7503 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7505 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7506 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7509 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7510 if ( !Texture_fp ) return;
7512 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7513 if ( !Time_fp ) return;
7515 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7516 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7518 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7519 if ( model_used[i] ) {
7520 Time_model( model_id[i] );
7524 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7525 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7534 // Call this function when you want to inform the player that a feature is not
7535 // enabled in the DEMO version of FreSpace
7536 void game_feature_not_in_demo_popup()
7538 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7541 // format the specified time (fixed point) into a nice string
7542 void game_format_time(fix m_time,char *time_str)
7545 int hours,minutes,seconds;
7548 mtime = f2fl(m_time);
7550 // get the hours, minutes and seconds
7551 hours = (int)(mtime / 3600.0f);
7553 mtime -= (3600.0f * (float)hours);
7555 seconds = (int)mtime%60;
7556 minutes = (int)mtime/60;
7558 // print the hour if necessary
7560 sprintf(time_str,XSTR( "%d:", 201),hours);
7561 // if there are less than 10 minutes, print a leading 0
7563 strcpy(tmp,NOX("0"));
7564 strcat(time_str,tmp);
7568 // print the minutes
7570 sprintf(tmp,XSTR( "%d:", 201),minutes);
7571 strcat(time_str,tmp);
7573 sprintf(time_str,XSTR( "%d:", 201),minutes);
7576 // print the seconds
7578 strcpy(tmp,NOX("0"));
7579 strcat(time_str,tmp);
7581 sprintf(tmp,"%d",seconds);
7582 strcat(time_str,tmp);
7585 // Stuff version string in *str.
7586 void get_version_string(char *str)
7589 if ( FS_VERSION_BUILD == 0 ) {
7590 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7592 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7595 #if defined (FS2_DEMO)
7597 #elif defined (OEM_BUILD)
7598 strcat(str, " (OEM)");
7604 char myname[_MAX_PATH];
7605 int namelen, major, minor, build, waste;
7606 unsigned int buf_size;
7612 // Find my EXE file name
7613 hMod = GetModuleHandle(NULL);
7614 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7616 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7617 infop = (char *)malloc(version_size);
7618 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7620 // get the product version
7621 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7622 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7624 sprintf(str,"Dv%d.%02d",major, minor);
7626 sprintf(str,"v%d.%02d",major, minor);
7631 void get_version_string_short(char *str)
7633 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7636 // ----------------------------------------------------------------
7638 // OEM UPSELL SCREENS BEGIN
7640 // ----------------------------------------------------------------
7641 #if defined(OEM_BUILD)
7643 #define NUM_OEM_UPSELL_SCREENS 3
7644 #define OEM_UPSELL_SCREEN_DELAY 10000
7646 static int Oem_upsell_bitmaps_loaded = 0;
7647 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7648 static int Oem_upsell_screen_number = 0;
7649 static int Oem_upsell_show_next_bitmap_time;
7652 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7665 static int Oem_normal_cursor = -1;
7666 static int Oem_web_cursor = -1;
7667 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7668 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7670 void oem_upsell_next_screen()
7672 Oem_upsell_screen_number++;
7673 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7674 // extra long delay, mouse shown on last upsell
7675 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7679 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7683 void oem_upsell_load_bitmaps()
7687 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7688 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7692 void oem_upsell_unload_bitmaps()
7696 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7697 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7698 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7703 Oem_upsell_bitmaps_loaded = 0;
7706 // clickable hotspot on 3rd OEM upsell screen
7707 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7709 28, 350, 287, 96 // x, y, w, h
7712 45, 561, 460, 152 // x, y, w, h
7716 void oem_upsell_show_screens()
7718 int current_time, k;
7721 if ( !Oem_upsell_bitmaps_loaded ) {
7722 oem_upsell_load_bitmaps();
7723 Oem_upsell_bitmaps_loaded = 1;
7726 // may use upsell screens more than once
7727 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7728 Oem_upsell_screen_number = 0;
7734 int nframes; // used to pass, not really needed (should be 1)
7735 Oem_normal_cursor = gr_get_cursor_bitmap();
7736 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7737 Assert(Oem_web_cursor >= 0);
7738 if (Oem_web_cursor < 0) {
7739 Oem_web_cursor = Oem_normal_cursor;
7744 //oem_reset_trailer_timer();
7746 current_time = timer_get_milliseconds();
7751 // advance screen on keypress or timeout
7752 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7753 oem_upsell_next_screen();
7756 // check if we are done
7757 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7758 Oem_upsell_screen_number--;
7761 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7766 // show me the upsell
7767 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7768 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7772 // if this is the 3rd upsell, make it clickable, d00d
7773 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7775 int button_state = mouse_get_pos(&mx, &my);
7776 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])
7777 && (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]) )
7780 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7783 if (button_state & MOUSE_LEFT_BUTTON) {
7785 multi_pxo_url(OEM_UPSELL_URL);
7789 // switch cursor back to normal one
7790 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7795 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7805 oem_upsell_unload_bitmaps();
7807 // switch cursor back to normal one
7808 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7812 #endif // defined(OEM_BUILD)
7813 // ----------------------------------------------------------------
7815 // OEM UPSELL SCREENS END
7817 // ----------------------------------------------------------------
7821 // ----------------------------------------------------------------
7823 // DEMO UPSELL SCREENS BEGIN
7825 // ----------------------------------------------------------------
7829 //#define NUM_DEMO_UPSELL_SCREENS 4
7831 #define NUM_DEMO_UPSELL_SCREENS 2
7832 #define DEMO_UPSELL_SCREEN_DELAY 3000
7834 static int Demo_upsell_bitmaps_loaded = 0;
7835 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7836 static int Demo_upsell_screen_number = 0;
7837 static int Demo_upsell_show_next_bitmap_time;
7840 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7853 void demo_upsell_next_screen()
7855 Demo_upsell_screen_number++;
7856 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7857 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7859 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7863 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7864 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7865 #ifndef HARDWARE_ONLY
7866 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7873 void demo_upsell_load_bitmaps()
7877 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7878 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7882 void demo_upsell_unload_bitmaps()
7886 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7887 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7888 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7893 Demo_upsell_bitmaps_loaded = 0;
7896 void demo_upsell_show_screens()
7898 int current_time, k;
7901 if ( !Demo_upsell_bitmaps_loaded ) {
7902 demo_upsell_load_bitmaps();
7903 Demo_upsell_bitmaps_loaded = 1;
7906 // may use upsell screens more than once
7907 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7908 Demo_upsell_screen_number = 0;
7915 demo_reset_trailer_timer();
7917 current_time = timer_get_milliseconds();
7924 // don't time out, wait for keypress
7926 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7927 demo_upsell_next_screen();
7932 demo_upsell_next_screen();
7935 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7936 Demo_upsell_screen_number--;
7939 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7944 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7945 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7950 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7960 demo_upsell_unload_bitmaps();
7965 // ----------------------------------------------------------------
7967 // DEMO UPSELL SCREENS END
7969 // ----------------------------------------------------------------
7972 // ----------------------------------------------------------------
7974 // Subspace Ambient Sound START
7976 // ----------------------------------------------------------------
7978 static int Subspace_ambient_left_channel = -1;
7979 static int Subspace_ambient_right_channel = -1;
7982 void game_start_subspace_ambient_sound()
7984 if ( Subspace_ambient_left_channel < 0 ) {
7985 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7988 if ( Subspace_ambient_right_channel < 0 ) {
7989 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7993 void game_stop_subspace_ambient_sound()
7995 if ( Subspace_ambient_left_channel >= 0 ) {
7996 snd_stop(Subspace_ambient_left_channel);
7997 Subspace_ambient_left_channel = -1;
8000 if ( Subspace_ambient_right_channel >= 0 ) {
8001 snd_stop(Subspace_ambient_right_channel);
8002 Subspace_ambient_right_channel = -1;
8006 // ----------------------------------------------------------------
8008 // Subspace Ambient Sound END
8010 // ----------------------------------------------------------------
8012 // ----------------------------------------------------------------
8014 // CDROM detection code START
8016 // ----------------------------------------------------------------
8018 #define CD_SIZE_72_MINUTE_MAX (697000000)
8020 uint game_get_cd_used_space(char *path)
8024 char use_path[512] = "";
8025 char sub_path[512] = "";
8026 WIN32_FIND_DATA find;
8029 // recurse through all files and directories
8030 strcpy(use_path, path);
8031 strcat(use_path, "*.*");
8032 find_handle = FindFirstFile(use_path, &find);
8035 if(find_handle == INVALID_HANDLE_VALUE){
8041 // subdirectory. make sure to ignore . and ..
8042 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8044 strcpy(sub_path, path);
8045 strcat(sub_path, find.cFileName);
8046 strcat(sub_path, "\\");
8047 total += game_get_cd_used_space(sub_path);
8049 total += (uint)find.nFileSizeLow;
8051 } while(FindNextFile(find_handle, &find));
8054 FindClose(find_handle);
8066 // if volume_name is non-null, the CD name must match that
8067 int find_freespace_cd(char *volume_name)
8070 char oldpath[MAX_PATH];
8074 int volume_match = 0;
8078 GetCurrentDirectory(MAX_PATH, oldpath);
8080 for (i = 0; i < 26; i++)
8086 path[0] = (char)('A'+i);
8087 if (GetDriveType(path) == DRIVE_CDROM) {
8089 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8090 nprintf(("CD", "CD volume: %s\n", volume));
8092 // check for any CD volume
8093 int volume1_present = 0;
8094 int volume2_present = 0;
8095 int volume3_present = 0;
8097 char full_check[512] = "";
8099 // look for setup.exe
8100 strcpy(full_check, path);
8101 strcat(full_check, "setup.exe");
8102 find_handle = _findfirst(full_check, &find);
8103 if(find_handle != -1){
8104 volume1_present = 1;
8105 _findclose(find_handle);
8108 // look for intro.mve
8109 strcpy(full_check, path);
8110 strcat(full_check, "intro.mve");
8111 find_handle = _findfirst(full_check, &find);
8112 if(find_handle != -1){
8113 volume2_present = 1;
8114 _findclose(find_handle);
8117 // look for endpart1.mve
8118 strcpy(full_check, path);
8119 strcat(full_check, "endpart1.mve");
8120 find_handle = _findfirst(full_check, &find);
8121 if(find_handle != -1){
8122 volume3_present = 1;
8123 _findclose(find_handle);
8126 // see if we have the specific CD we're looking for
8127 if ( volume_name ) {
8129 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8133 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8137 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8141 if ( volume1_present || volume2_present || volume3_present ) {
8146 // 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
8147 if ( volume_match ){
8149 // 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
8150 if(volume2_present || volume3_present) {
8151 // first step - check to make sure its a cdrom
8152 if(GetDriveType(path) != DRIVE_CDROM){
8156 #if !defined(OEM_BUILD)
8157 // oem not on 80 min cds, so dont check tha size
8159 uint used_space = game_get_cd_used_space(path);
8160 if(used_space < CD_SIZE_72_MINUTE_MAX){
8163 #endif // !defined(OEM_BUILD)
8171 #endif // RELEASE_REAL
8177 SetCurrentDirectory(oldpath);
8186 int set_cdrom_path(int drive_num)
8190 if (drive_num < 0) { //no CD
8192 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8195 strcpy(Game_CDROM_dir,""); //set directory
8199 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8215 i = find_freespace_cd();
8217 rval = set_cdrom_path(i);
8221 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8223 nprintf(("CD", "FreeSpace CD not found\n"));
8231 int Last_cd_label_found = 0;
8232 char Last_cd_label[256];
8234 int game_cd_changed()
8241 if ( strlen(Game_CDROM_dir) == 0 ) {
8245 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8247 if ( found != Last_cd_label_found ) {
8248 Last_cd_label_found = found;
8250 mprintf(( "CD '%s' was inserted\n", label ));
8253 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8257 if ( Last_cd_label_found ) {
8258 if ( !stricmp( Last_cd_label, label )) {
8259 //mprintf(( "CD didn't change\n" ));
8261 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8265 // none found before, none found now.
8266 //mprintf(( "still no CD...\n" ));
8270 Last_cd_label_found = found;
8272 strcpy( Last_cd_label, label );
8274 strcpy( Last_cd_label, "" );
8283 // check if _any_ FreeSpace2 CDs are in the drive
8284 // return: 1 => CD now in drive
8285 // 0 => Could not find CD, they refuse to put it in the drive
8286 int game_do_cd_check(char *volume_name)
8288 #if !defined(GAME_CD_CHECK)
8294 int num_attempts = 0;
8295 int refresh_files = 0;
8297 int path_set_ok, popup_rval;
8299 cd_drive_num = find_freespace_cd(volume_name);
8300 path_set_ok = set_cdrom_path(cd_drive_num);
8301 if ( path_set_ok ) {
8303 if ( refresh_files ) {
8315 // no CD found, so prompt user
8316 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8318 if ( popup_rval != 1 ) {
8323 if ( num_attempts++ > 5 ) {
8334 // check if _any_ FreeSpace2 CDs are in the drive
8335 // return: 1 => CD now in drive
8336 // 0 => Could not find CD, they refuse to put it in the drive
8337 int game_do_cd_check_specific(char *volume_name, int cdnum)
8342 int num_attempts = 0;
8343 int refresh_files = 0;
8345 int path_set_ok, popup_rval;
8347 cd_drive_num = find_freespace_cd(volume_name);
8348 path_set_ok = set_cdrom_path(cd_drive_num);
8349 if ( path_set_ok ) {
8351 if ( refresh_files ) {
8362 // no CD found, so prompt user
8363 #if defined(DVD_MESSAGE_HACK)
8364 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8366 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8369 if ( popup_rval != 1 ) {
8374 if ( num_attempts++ > 5 ) {
8384 // only need to do this in RELEASE_REAL
8385 int game_do_cd_mission_check(char *filename)
8391 fs_builtin_mission *m = game_find_builtin_mission(filename);
8393 // check for changed CD
8394 if(game_cd_changed()){
8399 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8403 // not builtin, so do a general check (any FS2 CD will do)
8405 return game_do_cd_check();
8408 // does not have any CD requirement, do a general check
8409 if(strlen(m->cd_volume) <= 0){
8410 return game_do_cd_check();
8414 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8416 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8418 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8421 return game_do_cd_check();
8424 // did we find the cd?
8425 if(find_freespace_cd(m->cd_volume) >= 0){
8429 // make sure the volume exists
8430 int num_attempts = 0;
8431 int refresh_files = 0;
8433 int path_set_ok, popup_rval;
8435 cd_drive_num = find_freespace_cd(m->cd_volume);
8436 path_set_ok = set_cdrom_path(cd_drive_num);
8437 if ( path_set_ok ) {
8439 if ( refresh_files ) {
8446 // no CD found, so prompt user
8447 #if defined(DVD_MESSAGE_HACK)
8448 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8450 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8454 if ( popup_rval != 1 ) {
8459 if ( num_attempts++ > 5 ) {
8471 // ----------------------------------------------------------------
8473 // CDROM detection code END
8475 // ----------------------------------------------------------------
8477 // ----------------------------------------------------------------
8478 // SHIPS TBL VERIFICATION STUFF
8481 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8482 #define NUM_SHIPS_TBL_CHECKSUMS 1
8484 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8485 -463907578, // US - beta 1
8486 1696074201, // FS2 demo
8489 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8490 // -1022810006, // 1.0 FULL
8491 -1254285366 // 1.2 FULL (German)
8494 void verify_ships_tbl()
8498 Game_ships_tbl_valid = 1;
8504 // detect if the packfile exists
8505 CFILE *detect = cfopen("ships.tbl", "rb");
8506 Game_ships_tbl_valid = 0;
8510 Game_ships_tbl_valid = 0;
8514 // get the long checksum of the file
8516 cfseek(detect, 0, SEEK_SET);
8517 cf_chksum_long(detect, &file_checksum);
8521 // now compare the checksum/filesize against known #'s
8522 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8523 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8524 Game_ships_tbl_valid = 1;
8531 DCF(shipspew, "display the checksum for the current ships.tbl")
8534 CFILE *detect = cfopen("ships.tbl", "rb");
8535 // get the long checksum of the file
8537 cfseek(detect, 0, SEEK_SET);
8538 cf_chksum_long(detect, &file_checksum);
8541 dc_printf("%d", file_checksum);
8544 // ----------------------------------------------------------------
8545 // WEAPONS TBL VERIFICATION STUFF
8548 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8549 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8551 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8552 141718090, // US - beta 1
8553 -266420030, // demo 1
8556 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8557 // 399297860, // 1.0 FULL
8558 -553984927 // 1.2 FULL (german)
8561 void verify_weapons_tbl()
8565 Game_weapons_tbl_valid = 1;
8571 // detect if the packfile exists
8572 CFILE *detect = cfopen("weapons.tbl", "rb");
8573 Game_weapons_tbl_valid = 0;
8577 Game_weapons_tbl_valid = 0;
8581 // get the long checksum of the file
8583 cfseek(detect, 0, SEEK_SET);
8584 cf_chksum_long(detect, &file_checksum);
8588 // now compare the checksum/filesize against known #'s
8589 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8590 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8591 Game_weapons_tbl_valid = 1;
8598 DCF(wepspew, "display the checksum for the current weapons.tbl")
8601 CFILE *detect = cfopen("weapons.tbl", "rb");
8602 // get the long checksum of the file
8604 cfseek(detect, 0, SEEK_SET);
8605 cf_chksum_long(detect, &file_checksum);
8608 dc_printf("%d", file_checksum);
8611 // if the game is running using hacked data
8612 int game_hacked_data()
8615 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8623 void display_title_screen()
8625 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8626 ///int title_bitmap;
8629 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8630 if (title_bitmap == -1) {
8635 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8636 extern void d3d_start_frame();
8641 gr_set_bitmap(title_bitmap);
8647 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8648 extern void d3d_stop_frame();
8655 bm_unload(title_bitmap);
8656 #endif // FS2_DEMO || OEM_BUILD
8659 // return true if the game is running with "low memory", which is less than 48MB
8660 bool game_using_low_mem()
8662 if (Use_low_mem == 0) {